From 14158070bf8b3f831702061ffd657c84179fc639 Mon Sep 17 00:00:00 2001 From: Trustin Lee Date: Tue, 28 May 2013 20:40:19 +0900 Subject: [PATCH] Revamp the core API to reduce memory footprint and consumption The API changes made so far turned out to increase the memory footprint and consumption while our intention was actually decreasing them. Memory consumption issue: When there are many connections which does not exchange data frequently, the old Netty 4 API spent a lot more memory than 3 because it always allocates per-handler buffer for each connection unless otherwise explicitly stated by a user. In a usual real world load, a client doesn't always send requests without pausing, so the idea of having a buffer whose life cycle if bound to the life cycle of a connection didn't work as expected. Memory footprint issue: The old Netty 4 API decreased overall memory footprint by a great deal in many cases. It was mainly because the old Netty 4 API did not allocate a new buffer and event object for each read. Instead, it created a new buffer for each handler in a pipeline. This works pretty well as long as the number of handlers in a pipeline is only a few. However, for a highly modular application with many handlers which handles connections which lasts for relatively short period, it actually makes the memory footprint issue much worse. Changes: All in all, this is about retaining all the good changes we made in 4 so far such as better thread model and going back to the way how we dealt with message events in 3. To fix the memory consumption/footprint issue mentioned above, we made a hard decision to break the backward compatibility again with the following changes: - Remove MessageBuf - Merge Buf into ByteBuf - Merge ChannelInboundByte/MessageHandler and ChannelStateHandler into ChannelInboundHandler - Similar changes were made to the adapter classes - Merge ChannelOutboundByte/MessageHandler and ChannelOperationHandler into ChannelOutboundHandler - Similar changes were made to the adapter classes - Introduce MessageList which is similar to `MessageEvent` in Netty 3 - Replace inboundBufferUpdated(ctx) with messageReceived(ctx, MessageList) - Replace flush(ctx, promise) with write(ctx, MessageList, promise) - Remove ByteToByteEncoder/Decoder/Codec - Replaced by MessageToByteEncoder, ByteToMessageDecoder, and ByteMessageCodec - Merge EmbeddedByteChannel and EmbeddedMessageChannel into EmbeddedChannel - Add SimpleChannelInboundHandler which is sometimes more useful than ChannelInboundHandlerAdapter - Bring back Channel.isWritable() from Netty 3 - Add ChannelInboundHandler.channelWritabilityChanges() event - Add RecvByteBufAllocator configuration property - Similar to ReceiveBufferSizePredictor in Netty 3 - Some existing configuration properties such as DatagramChannelConfig.receivePacketSize is gone now. - Remove suspend/resumeIntermediaryDeallocation() in ByteBuf This change would have been impossible without @normanmaurer's help. He fixed, ported, and improved many parts of the changes. --- all/pom.xml | 2 +- buffer/pom.xml | 2 +- .../java/io/netty/buffer/AbstractByteBuf.java | 17 +- .../netty/buffer/AbstractDerivedByteBuf.java | 10 - .../io/netty/buffer/AbstractMessageBuf.java | 258 ---- buffer/src/main/java/io/netty/buffer/Buf.java | 58 - .../main/java/io/netty/buffer/ByteBuf.java | 33 +- .../buffer/{BufUtil.java => ByteBufUtil.java} | 32 +- .../io/netty/buffer/CompositeByteBuf.java | 6 - .../netty/buffer/DefaultCompositeByteBuf.java | 34 +- .../io/netty/buffer/DefaultMessageBuf.java | 337 ----- .../java/io/netty/buffer/EmptyByteBuf.java | 15 - .../io/netty/buffer/FilteredMessageBuf.java | 229 --- .../main/java/io/netty/buffer/MessageBuf.java | 50 - .../java/io/netty/buffer/PooledByteBuf.java | 50 +- .../netty/buffer/QueueBackedMessageBuf.java | 132 -- .../netty/buffer/ReadOnlyByteBufferBuf.java | 10 - .../java/io/netty/buffer/SwappedByteBuf.java | 53 +- .../main/java/io/netty/buffer/Unpooled.java | 38 +- .../netty/buffer/UnpooledDirectByteBuf.java | 34 +- .../io/netty/buffer/UnpooledHeapByteBuf.java | 10 - .../buffer/UnpooledUnsafeDirectByteBuf.java | 34 +- .../io/netty/buffer/UnreleasableByteBuf.java | 17 - .../buffer/AbstractCompositeByteBufTest.java | 42 +- .../java/io/netty/buffer/UnpooledTest.java | 40 +- codec-http/pom.xml | 2 +- .../handler/codec/http/HttpClientCodec.java | 53 +- .../codec/http/HttpContentCompressor.java | 4 +- .../codec/http/HttpContentDecoder.java | 29 +- .../codec/http/HttpContentDecompressor.java | 8 +- .../codec/http/HttpContentEncoder.java | 37 +- .../codec/http/HttpObjectAggregator.java | 8 +- .../handler/codec/http/HttpObjectDecoder.java | 8 +- .../handler/codec/http/HttpObjectEncoder.java | 4 +- .../handler/codec/http/HttpServerCodec.java | 31 +- .../multipart/HttpPostRequestDecoder.java | 1 - .../multipart/HttpPostRequestEncoder.java | 4 +- .../websocketx/WebSocket00FrameDecoder.java | 4 +- .../websocketx/WebSocket08FrameDecoder.java | 463 +++--- .../websocketx/WebSocketClientHandshaker.java | 8 +- .../WebSocketClientHandshaker00.java | 8 +- .../WebSocketClientHandshaker07.java | 8 +- .../WebSocketClientHandshaker08.java | 8 +- .../WebSocketClientHandshaker13.java | 8 +- .../WebSocketClientProtocolHandler.java | 9 +- ...bSocketClientProtocolHandshakeHandler.java | 10 +- .../websocketx/WebSocketFrameAggregator.java | 4 +- .../websocketx/WebSocketProtocolHandler.java | 11 +- .../websocketx/WebSocketServerHandshaker.java | 8 +- .../WebSocketServerHandshaker00.java | 8 +- .../WebSocketServerHandshaker07.java | 8 +- .../WebSocketServerHandshaker08.java | 8 +- .../WebSocketServerHandshaker13.java | 8 +- .../WebSocketServerProtocolHandler.java | 28 +- ...bSocketServerProtocolHandshakeHandler.java | 59 +- .../handler/codec/spdy/SpdyFrameCodec.java | 33 +- .../handler/codec/spdy/SpdyFrameDecoder.java | 6 +- .../handler/codec/spdy/SpdyHttpCodec.java | 27 +- .../handler/codec/spdy/SpdyHttpDecoder.java | 4 +- .../handler/codec/spdy/SpdyHttpEncoder.java | 4 +- .../spdy/SpdyHttpResponseStreamIdHandler.java | 12 +- .../handler/codec/spdy/SpdyOrHttpChooser.java | 36 +- .../codec/spdy/SpdySessionHandler.java | 118 +- .../codec/http/HttpClientCodecTest.java | 10 +- .../codec/http/HttpContentCompressorTest.java | 4 +- .../codec/http/HttpContentEncoderTest.java | 27 +- .../codec/http/HttpInvalidMessageTest.java | 17 +- .../codec/http/HttpObjectAggregatorTest.java | 10 +- .../codec/http/HttpServerCodecTest.java | 7 +- .../WebSocketFrameAggregatorTest.java | 10 +- .../WebSocketServerHandshaker00Test.java | 8 +- .../WebSocketServerHandshaker08Test.java | 8 +- .../WebSocketServerHandshaker13Test.java | 8 +- .../WebSocketServerProtocolHandlerTest.java | 86 +- .../codec/spdy/SpdySessionHandlerTest.java | 64 +- codec-socks/pom.xml | 2 +- .../codec/socks/SocksAuthRequestDecoder.java | 4 +- .../codec/socks/SocksAuthResponseDecoder.java | 4 +- .../codec/socks/SocksCmdRequestDecoder.java | 4 +- .../codec/socks/SocksCmdResponseDecoder.java | 4 +- .../codec/socks/SocksInitRequestDecoder.java | 4 +- .../codec/socks/SocksInitResponseDecoder.java | 4 +- .../socks/SocksAuthRequestDecoderTest.java | 4 +- .../socks/SocksAuthResponseDecoderTest.java | 4 +- .../socks/SocksCmdRequestDecoderTest.java | 4 +- .../socks/SocksCmdResponseDecoderTest.java | 8 +- .../codec/socks/SocksCommonTestUtils.java | 4 +- codec/pom.xml | 2 +- .../netty/handler/codec/ByteToByteCodec.java | 127 -- .../handler/codec/ByteToByteDecoder.java | 142 -- .../handler/codec/ByteToByteEncoder.java | 150 -- .../handler/codec/ByteToMessageCodec.java | 50 +- .../handler/codec/ByteToMessageDecoder.java | 193 ++- .../codec/DelimiterBasedFrameDecoder.java | 4 +- .../codec/FixedLengthFrameDecoder.java | 34 +- .../codec/LengthFieldBasedFrameDecoder.java | 4 +- .../handler/codec/LineBasedFrameDecoder.java | 4 +- .../handler/codec/MessageToByteEncoder.java | 73 +- .../handler/codec/MessageToMessageCodec.java | 47 +- .../codec/MessageToMessageDecoder.java | 60 +- .../codec/MessageToMessageEncoder.java | 64 +- .../netty/handler/codec/OutputMessageBuf.java | 177 --- .../netty/handler/codec/ReplayingDecoder.java | 111 +- .../handler/codec/ReplayingDecoderBuffer.java | 16 - .../handler/codec/base64/Base64Decoder.java | 4 +- .../handler/codec/base64/Base64Encoder.java | 12 +- .../handler/codec/bytes/ByteArrayDecoder.java | 5 +- .../handler/codec/bytes/ByteArrayEncoder.java | 23 +- .../compression/CompressionException.java | 7 +- .../compression/DecompressionException.java | 53 + .../codec/compression/JZlibDecoder.java | 42 +- .../codec/compression/JZlibEncoder.java | 24 +- .../codec/compression/JdkZlibEncoder.java | 5 +- .../handler/codec/compression/Snappy.java | 34 +- .../compression/SnappyFramedDecoder.java | 43 +- .../compression/SnappyFramedEncoder.java | 12 +- .../codec/compression/ZlibDecoder.java | 4 +- .../codec/compression/ZlibEncoder.java | 4 +- .../CompatibleMarshallingDecoder.java | 6 +- .../codec/protobuf/ProtobufDecoder.java | 4 +- .../codec/protobuf/ProtobufEncoder.java | 7 +- .../ProtobufVarint32FrameDecoder.java | 4 +- .../handler/codec/string/StringDecoder.java | 4 +- .../handler/codec/string/StringEncoder.java | 18 +- .../codec/DelimiterBasedFrameDecoderTest.java | 23 +- .../codec/LineBasedFrameDecoderTest.java | 12 +- .../handler/codec/ReplayingDecoderTest.java | 19 +- .../codec/bytes/ByteArrayDecoderTest.java | 6 +- .../codec/bytes/ByteArrayEncoderTest.java | 9 +- .../handler/codec/compression/JZlibTest.java | 50 +- .../compression/SnappyFramedDecoderTest.java | 24 +- .../compression/SnappyFramedEncoderTest.java | 19 +- .../compression/SnappyIntegrationTest.java | 24 +- .../handler/codec/compression/SnappyTest.java | 8 +- .../frame/DelimiterBasedFrameDecoderTest.java | 10 +- .../LengthFieldBasedFrameDecoderTest.java | 10 +- .../codec/frame/LengthFieldPrependerTest.java | 21 +- ...tractCompatibleMarshallingDecoderTest.java | 12 +- ...tractCompatibleMarshallingEncoderTest.java | 6 +- .../RiverMarshallingDecoderTest.java | 4 +- .../SerialMarshallingDecoderTest.java | 4 +- .../ProtobufVarint32FrameDecoderTest.java | 14 +- ...tobufVarint32LengthFieldPrependerTest.java | 19 +- common/pom.xml | 2 +- .../src/main/java/io/netty/util/Recycler.java | 90 ++ .../io/netty/util/ResourceLeakDetector.java | 6 +- example/pom.xml | 2 +- .../example/applet/AppletDiscardServer.java | 14 +- .../example/discard/DiscardClientHandler.java | 23 +- .../example/discard/DiscardServerHandler.java | 11 +- .../io/netty/example/echo/EchoClient.java | 4 +- .../netty/example/echo/EchoClientHandler.java | 11 +- .../io/netty/example/echo/EchoServer.java | 2 +- .../netty/example/echo/EchoServerHandler.java | 12 +- .../example/factorial/BigIntegerDecoder.java | 4 +- .../factorial/FactorialClientHandler.java | 10 +- .../factorial/FactorialServerHandler.java | 20 +- .../example/filetransfer/FileServer.java | 54 +- .../file/HttpStaticFileServerHandler.java | 167 +-- .../http/snoop/HttpSnoopClientHandler.java | 65 +- .../http/snoop/HttpSnoopServerHandler.java | 49 +- .../http/upload/HttpUploadClientHandler.java | 63 +- .../http/upload/HttpUploadServerHandler.java | 186 +-- .../autobahn/AutobahnServerHandler.java | 45 +- .../client/WebSocketClientHandler.java | 53 +- .../html5/CustomTextFrameHandler.java | 4 +- .../server/WebSocketServerHandler.java | 25 +- .../sslserver/WebSocketSslServerHandler.java | 25 +- .../localecho/LocalEchoClientHandler.java | 15 +- .../localecho/LocalEchoServerHandler.java | 9 +- .../objectecho/ObjectEchoClientHandler.java | 9 +- .../objectecho/ObjectEchoServerHandler.java | 10 +- .../PortUnificationServerHandler.java | 7 +- .../proxy/HexDumpProxyBackendHandler.java | 15 +- .../proxy/HexDumpProxyFrontendHandler.java | 15 +- .../qotm/QuoteOfTheMomentClientHandler.java | 21 +- .../qotm/QuoteOfTheMomentServerHandler.java | 20 +- .../netty/example/rxtx/RxtxClientHandler.java | 19 +- .../example/sctp/SctpEchoClientHandler.java | 13 +- .../example/sctp/SctpEchoServerHandler.java | 13 +- .../securechat/SecureChatClientHandler.java | 12 +- .../securechat/SecureChatServerHandler.java | 36 +- .../socksproxy/DirectClientHandler.java | 9 +- .../example/socksproxy/RelayHandler.java | 15 +- .../socksproxy/SocksServerConnectHandler.java | 4 +- .../socksproxy/SocksServerHandler.java | 7 +- .../example/socksproxy/SocksServerUtils.java | 3 +- .../example/telnet/TelnetClientHandler.java | 7 +- .../example/telnet/TelnetServerHandler.java | 49 +- .../udt/echo/bytes/ByteEchoClientHandler.java | 29 +- .../udt/echo/bytes/ByteEchoServerHandler.java | 23 +- .../echo/message/MsgEchoClientHandler.java | 27 +- .../echo/message/MsgEchoServerHandler.java | 15 +- .../echo/rendezvous/MsgEchoPeerHandler.java | 26 +- .../rendezvousBytes/ByteEchoPeerHandler.java | 26 +- .../example/uptime/UptimeClientHandler.java | 10 +- .../worldclock/WorldClockClientHandler.java | 12 +- .../worldclock/WorldClockServerHandler.java | 47 +- handler/pom.xml | 7 +- .../handler/logging/ByteLoggingHandler.java | 51 +- .../netty/handler/logging/LoggingHandler.java | 161 ++- .../logging/MessageLoggingHandler.java | 74 +- .../java/io/netty/handler/ssl/SslHandler.java | 451 +++--- .../handler/stream/ChunkedMessageInput.java | 4 +- .../handler/stream/ChunkedWriteHandler.java | 49 +- .../handler/timeout/IdleStateHandler.java | 30 +- .../handler/timeout/ReadTimeoutHandler.java | 9 +- .../handler/timeout/WriteTimeoutHandler.java | 16 +- .../AbstractTrafficShapingHandler.java | 53 +- .../stream/ChunkedWriteHandlerTest.java | 21 +- microbench/pom.xml | 2 +- pom.xml | 2 +- tarball/pom.xml | 2 +- testsuite-osgi/pom.xml | 2 +- testsuite-osgi/testsuite-osgi-deps/pom.xml | 2 +- testsuite-osgi/testsuite-osgi-exam/pom.xml | 2 +- testsuite-osgi/testsuite-osgi-split/pom.xml | 2 +- testsuite/pom.xml | 2 +- .../transport/sctp/SctpEchoTest.java | 63 +- .../socket/DatagramMulticastTest.java | 20 +- .../transport/socket/DatagramUnicastTest.java | 20 +- .../socket/ServerSocketSuspendTest.java | 10 +- .../socket/SocketBufReleaseTest.java | 9 +- .../transport/socket/SocketEchoTest.java | 88 +- .../socket/SocketFileRegionTest.java | 41 +- .../socket/SocketFixedLengthEchoTest.java | 37 +- .../socket/SocketObjectEchoTest.java | 22 +- .../SocketShutdownOutputByPeerTest.java | 12 +- .../SocketShutdownOutputBySelfTest.java | 12 +- .../transport/socket/SocketSpdyEchoTest.java | 34 +- .../transport/socket/SocketSslEchoTest.java | 43 +- .../transport/socket/SocketStartTlsTest.java | 53 +- .../socket/SocketStringEchoTest.java | 25 +- .../socket/WriteBeforeRegisteredTest.java | 9 +- .../udt/UDTClientServerConnectionTest.java | 31 +- transport-rxtx/pom.xml | 7 +- .../rxtx/DefaultRxtxChannelConfig.java | 16 +- .../netty/channel/rxtx/RxtxChannelConfig.java | 5 +- transport-sctp/pom.xml | 2 +- .../sctp/DefaultSctpChannelConfig.java | 17 +- .../sctp/DefaultSctpServerChannelConfig.java | 16 +- .../netty/channel/sctp/SctpChannelConfig.java | 8 +- .../io/netty/channel/sctp/SctpMessage.java | 4 +- .../channel/sctp/SctpServerChannelConfig.java | 8 +- .../channel/sctp/nio/NioSctpChannel.java | 20 +- .../sctp/nio/NioSctpServerChannel.java | 9 +- .../channel/sctp/oio/OioSctpChannel.java | 38 +- .../sctp/oio/OioSctpServerChannel.java | 41 +- .../sctp/SctpInboundByteStreamHandler.java | 11 +- .../sctp/SctpMessageCompletionHandler.java | 41 +- .../sctp/SctpOutboundByteStreamHandler.java | 22 +- transport-udt/pom.xml | 2 +- .../channel/udt/DefaultUdtChannelConfig.java | 18 +- .../udt/DefaultUdtServerChannelConfig.java | 9 +- .../netty/channel/udt/UdtChannelConfig.java | 7 +- .../channel/udt/UdtServerChannelConfig.java | 7 +- .../udt/nio/NioUdtAcceptorChannel.java | 5 +- .../udt/nio/NioUdtByteAcceptorChannel.java | 12 +- .../udt/nio/NioUdtByteConnectorChannel.java | 10 +- .../udt/nio/NioUdtMessageAcceptorChannel.java | 11 +- .../nio/NioUdtMessageConnectorChannel.java | 18 +- .../nio/NioUdtByteAcceptorChannelTest.java | 3 +- .../nio/NioUdtByteConnectorChannelTest.java | 5 +- .../nio/NioUdtByteRendezvousChannelTest.java | 3 +- .../nio/NioUdtMessageAcceptorChannelTest.java | 3 +- .../NioUdtMessageConnectorChannelTest.java | 3 +- .../NioUdtMessageRendezvousChannelTest.java | 3 +- .../netty/test/udt/util/EchoByteHandler.java | 36 +- .../test/udt/util/EchoMessageHandler.java | 32 +- transport/pom.xml | 2 +- .../io/netty/bootstrap/ServerBootstrap.java | 26 +- .../io/netty/channel/AbstractChannel.java | 392 ++--- .../netty/channel/AbstractServerChannel.java | 44 +- .../channel/AdaptiveRecvByteBufAllocator.java | 194 +++ .../main/java/io/netty/channel/Channel.java | 44 +- .../java/io/netty/channel/ChannelConfig.java | 58 +- .../netty/channel/ChannelDuplexHandler.java | 34 +- .../java/io/netty/channel/ChannelHandler.java | 12 +- .../netty/channel/ChannelHandlerContext.java | 108 +- .../io/netty/channel/ChannelHandlerUtil.java | 321 ----- .../channel/ChannelInboundByteHandler.java | 43 - .../ChannelInboundByteHandlerAdapter.java | 55 - .../netty/channel/ChannelInboundHandler.java | 58 +- ...java => ChannelInboundHandlerAdapter.java} | 43 +- .../netty/channel/ChannelInboundInvoker.java | 41 +- .../channel/ChannelInboundMessageHandler.java | 31 - .../ChannelInboundMessageHandlerAdapter.java | 117 -- .../io/netty/channel/ChannelInitializer.java | 9 +- .../io/netty/channel/ChannelMetadata.java | 18 +- .../channel/ChannelOperationHandler.java | 98 -- .../java/io/netty/channel/ChannelOption.java | 17 +- .../netty/channel/ChannelOutboundBuffer.java | 238 ++++ .../channel/ChannelOutboundByteHandler.java | 42 - .../ChannelOutboundByteHandlerAdapter.java | 51 - .../netty/channel/ChannelOutboundHandler.java | 75 +- ...ava => ChannelOutboundHandlerAdapter.java} | 31 +- .../netty/channel/ChannelOutboundInvoker.java | 135 +- .../ChannelOutboundMessageHandler.java | 34 - .../ChannelOutboundMessageHandlerAdapter.java | 109 -- .../io/netty/channel/ChannelPipeline.java | 80 +- .../io/netty/channel/ChannelStateHandler.java | 63 - .../channel/CombinedChannelDuplexHandler.java | 135 +- .../channel/DefaultAddressedEnvelope.java | 10 +- .../netty/channel/DefaultChannelConfig.java | 71 +- .../channel/DefaultChannelHandlerContext.java | 1258 ++--------------- .../netty/channel/DefaultChannelPipeline.java | 286 +--- .../io/netty/channel/DefaultFileRegion.java | 12 +- .../java/io/netty/channel/FileRegion.java | 5 + .../channel/FixedRecvByteBufAllocator.java | 69 + .../java/io/netty/channel/MessageList.java | 475 +++++++ .../netty/channel/MessageListProcessor.java | 24 +- .../netty/channel/RecvByteBufAllocator.java | 54 + .../channel/SimpleChannelInboundHandler.java | 89 ++ .../channel/aio/AioCompletionHandler.java | 28 +- .../io/netty/channel/aio/AioEventLoop.java | 7 +- .../channel/embedded/EmbeddedByteChannel.java | 82 -- ...eddedChannel.java => EmbeddedChannel.java} | 249 ++-- .../embedded/EmbeddedMessageChannel.java | 75 - .../io/netty/channel/group/ChannelGroup.java | 26 +- .../channel/group/DefaultChannelGroup.java | 30 +- .../io/netty/channel/local/LocalChannel.java | 52 +- .../channel/local/LocalServerChannel.java | 26 +- .../channel/nio/AbstractNioByteChannel.java | 209 ++- .../nio/AbstractNioMessageChannel.java | 101 +- .../channel/oio/AbstractOioByteChannel.java | 52 +- .../oio/AbstractOioMessageChannel.java | 75 +- .../channel/oio/OioByteStreamChannel.java | 12 +- .../socket/ChannelInputShutdownEvent.java | 4 +- .../channel/socket/DatagramChannelConfig.java | 19 +- .../socket/DefaultDatagramChannelConfig.java | 44 +- .../DefaultServerSocketChannelConfig.java | 16 +- .../socket/DefaultSocketChannelConfig.java | 16 +- .../socket/ServerSocketChannelConfig.java | 5 +- .../channel/socket/SocketChannelConfig.java | 9 +- .../socket/aio/AioServerSocketChannel.java | 42 +- .../aio/AioServerSocketChannelConfig.java | 17 +- .../channel/socket/aio/AioSocketChannel.java | 493 ++++--- .../socket/aio/AioSocketChannelConfig.java | 5 +- .../aio/DefaultAioSocketChannelConfig.java | 16 +- .../socket/nio/NioDatagramChannel.java | 34 +- .../socket/nio/NioServerSocketChannel.java | 9 +- .../channel/socket/nio/NioSocketChannel.java | 35 +- .../DefaultOioServerSocketChannelConfig.java | 9 +- .../oio/DefaultOioSocketChannelConfig.java | 9 +- .../socket/oio/OioDatagramChannel.java | 37 +- .../socket/oio/OioServerSocketChannel.java | 22 +- .../oio/OioServerSocketChannelConfig.java | 5 +- .../socket/oio/OioSocketChannelConfig.java | 5 +- .../io/netty/bootstrap/BootstrapTest.java | 16 +- .../netty/channel/AbstractEventLoopTest.java | 21 +- .../channel/DefaultChannelPipelineTest.java | 620 ++------ .../group/DefaultChannnelGroupTest.java | 8 +- .../local/LocalChannelRegistryTest.java | 14 +- .../local/LocalTransportThreadModelTest.java | 341 ++--- .../local/LocalTransportThreadModelTest2.java | 31 +- .../local/LocalTransportThreadModelTest3.java | 45 +- .../channel/nio/NioDatagramChannelTest.java | 10 +- 357 files changed, 6282 insertions(+), 10019 deletions(-) delete mode 100644 buffer/src/main/java/io/netty/buffer/AbstractMessageBuf.java delete mode 100644 buffer/src/main/java/io/netty/buffer/Buf.java rename buffer/src/main/java/io/netty/buffer/{BufUtil.java => ByteBufUtil.java} (94%) delete mode 100644 buffer/src/main/java/io/netty/buffer/DefaultMessageBuf.java delete mode 100644 buffer/src/main/java/io/netty/buffer/FilteredMessageBuf.java delete mode 100644 buffer/src/main/java/io/netty/buffer/MessageBuf.java delete mode 100644 buffer/src/main/java/io/netty/buffer/QueueBackedMessageBuf.java delete mode 100644 codec/src/main/java/io/netty/handler/codec/ByteToByteCodec.java delete mode 100644 codec/src/main/java/io/netty/handler/codec/ByteToByteDecoder.java delete mode 100644 codec/src/main/java/io/netty/handler/codec/ByteToByteEncoder.java delete mode 100644 codec/src/main/java/io/netty/handler/codec/OutputMessageBuf.java create mode 100644 codec/src/main/java/io/netty/handler/codec/compression/DecompressionException.java create mode 100644 common/src/main/java/io/netty/util/Recycler.java create mode 100644 transport/src/main/java/io/netty/channel/AdaptiveRecvByteBufAllocator.java delete mode 100644 transport/src/main/java/io/netty/channel/ChannelHandlerUtil.java delete mode 100644 transport/src/main/java/io/netty/channel/ChannelInboundByteHandler.java delete mode 100644 transport/src/main/java/io/netty/channel/ChannelInboundByteHandlerAdapter.java mode change 100644 => 100755 transport/src/main/java/io/netty/channel/ChannelInboundHandler.java rename transport/src/main/java/io/netty/channel/{ChannelStateHandlerAdapter.java => ChannelInboundHandlerAdapter.java} (63%) delete mode 100644 transport/src/main/java/io/netty/channel/ChannelInboundMessageHandler.java delete mode 100644 transport/src/main/java/io/netty/channel/ChannelInboundMessageHandlerAdapter.java delete mode 100644 transport/src/main/java/io/netty/channel/ChannelOperationHandler.java create mode 100644 transport/src/main/java/io/netty/channel/ChannelOutboundBuffer.java delete mode 100644 transport/src/main/java/io/netty/channel/ChannelOutboundByteHandler.java delete mode 100644 transport/src/main/java/io/netty/channel/ChannelOutboundByteHandlerAdapter.java rename transport/src/main/java/io/netty/channel/{ChannelOperationHandlerAdapter.java => ChannelOutboundHandlerAdapter.java} (68%) delete mode 100644 transport/src/main/java/io/netty/channel/ChannelOutboundMessageHandler.java delete mode 100644 transport/src/main/java/io/netty/channel/ChannelOutboundMessageHandlerAdapter.java delete mode 100755 transport/src/main/java/io/netty/channel/ChannelStateHandler.java create mode 100644 transport/src/main/java/io/netty/channel/FixedRecvByteBufAllocator.java create mode 100644 transport/src/main/java/io/netty/channel/MessageList.java rename buffer/src/main/java/io/netty/buffer/BufType.java => transport/src/main/java/io/netty/channel/MessageListProcessor.java (51%) create mode 100644 transport/src/main/java/io/netty/channel/RecvByteBufAllocator.java create mode 100644 transport/src/main/java/io/netty/channel/SimpleChannelInboundHandler.java delete mode 100644 transport/src/main/java/io/netty/channel/embedded/EmbeddedByteChannel.java rename transport/src/main/java/io/netty/channel/embedded/{AbstractEmbeddedChannel.java => EmbeddedChannel.java} (55%) delete mode 100644 transport/src/main/java/io/netty/channel/embedded/EmbeddedMessageChannel.java diff --git a/all/pom.xml b/all/pom.xml index 9df6cdb3da..7f4fce2356 100644 --- a/all/pom.xml +++ b/all/pom.xml @@ -20,7 +20,7 @@ io.netty netty-parent - 4.0.0.Final-SNAPSHOT + 4.0.0.CR4-SNAPSHOT netty-all diff --git a/buffer/pom.xml b/buffer/pom.xml index 310ebb5649..93e1e56f39 100644 --- a/buffer/pom.xml +++ b/buffer/pom.xml @@ -20,7 +20,7 @@ io.netty netty-parent - 4.0.0.Final-SNAPSHOT + 4.0.0.CR4-SNAPSHOT netty-buffer diff --git a/buffer/src/main/java/io/netty/buffer/AbstractByteBuf.java b/buffer/src/main/java/io/netty/buffer/AbstractByteBuf.java index 0828ab1e0b..21351f8a13 100644 --- a/buffer/src/main/java/io/netty/buffer/AbstractByteBuf.java +++ b/buffer/src/main/java/io/netty/buffer/AbstractByteBuf.java @@ -50,11 +50,6 @@ public abstract class AbstractByteBuf implements ByteBuf { this.maxCapacity = maxCapacity; } - @Override - public BufType type() { - return BufType.BYTE; - } - @Override public int maxCapacity() { return maxCapacity; @@ -971,17 +966,17 @@ public abstract class AbstractByteBuf implements ByteBuf { nioBuffer.flip(); } - return BufUtil.decodeString(nioBuffer, charset); + return ByteBufUtil.decodeString(nioBuffer, charset); } @Override public int indexOf(int fromIndex, int toIndex, byte value) { - return BufUtil.indexOf(this, fromIndex, toIndex, value); + return ByteBufUtil.indexOf(this, fromIndex, toIndex, value); } @Override public int indexOf(int fromIndex, int toIndex, ByteBufIndexFinder indexFinder) { - return BufUtil.indexOf(this, fromIndex, toIndex, indexFinder); + return ByteBufUtil.indexOf(this, fromIndex, toIndex, indexFinder); } @Override @@ -1027,7 +1022,7 @@ public abstract class AbstractByteBuf implements ByteBuf { @Override public int hashCode() { - return BufUtil.hashCode(this); + return ByteBufUtil.hashCode(this); } @Override @@ -1036,14 +1031,14 @@ public abstract class AbstractByteBuf implements ByteBuf { return true; } if (o instanceof ByteBuf) { - return BufUtil.equals(this, (ByteBuf) o); + return ByteBufUtil.equals(this, (ByteBuf) o); } return false; } @Override public int compareTo(ByteBuf that) { - return BufUtil.compare(this, that); + return ByteBufUtil.compare(this, that); } @Override diff --git a/buffer/src/main/java/io/netty/buffer/AbstractDerivedByteBuf.java b/buffer/src/main/java/io/netty/buffer/AbstractDerivedByteBuf.java index 4ef5961f55..13f906f6a6 100644 --- a/buffer/src/main/java/io/netty/buffer/AbstractDerivedByteBuf.java +++ b/buffer/src/main/java/io/netty/buffer/AbstractDerivedByteBuf.java @@ -52,14 +52,4 @@ public abstract class AbstractDerivedByteBuf extends AbstractByteBuf { public final boolean release(int decrement) { return unwrap().release(decrement); } - - @Override - public final ByteBuf suspendIntermediaryDeallocations() { - throw new UnsupportedOperationException("derived"); - } - - @Override - public final ByteBuf resumeIntermediaryDeallocations() { - throw new UnsupportedOperationException("derived"); - } } diff --git a/buffer/src/main/java/io/netty/buffer/AbstractMessageBuf.java b/buffer/src/main/java/io/netty/buffer/AbstractMessageBuf.java deleted file mode 100644 index ec9067239c..0000000000 --- a/buffer/src/main/java/io/netty/buffer/AbstractMessageBuf.java +++ /dev/null @@ -1,258 +0,0 @@ -/* - * Copyright 2013 The Netty Project - * - * The Netty Project licenses this file to you under the Apache License, - * version 2.0 (the "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. - */ - -package io.netty.buffer; - -import io.netty.util.internal.PlatformDependent; - -import java.util.AbstractQueue; -import java.util.Collection; -import java.util.concurrent.atomic.AtomicIntegerFieldUpdater; - -/** - * Abstract base class for {@link MessageBuf} implementations. - * @param - */ -public abstract class AbstractMessageBuf extends AbstractQueue implements MessageBuf { - - @SuppressWarnings("rawtypes") - private static final AtomicIntegerFieldUpdater refCntUpdater = - AtomicIntegerFieldUpdater.newUpdater(AbstractMessageBuf.class, "refCnt"); - - private static final long REFCNT_FIELD_OFFSET; - - static { - long refCntFieldOffset = -1; - try { - if (PlatformDependent.hasUnsafe()) { - refCntFieldOffset = PlatformDependent.objectFieldOffset( - AbstractMessageBuf.class.getDeclaredField("refCnt")); - } - } catch (Throwable t) { - // Ignored - } - - REFCNT_FIELD_OFFSET = refCntFieldOffset; - } - - private final int maxCapacity; - - @SuppressWarnings("FieldMayBeFinal") - private volatile int refCnt = 1; - - protected AbstractMessageBuf(int maxCapacity) { - if (maxCapacity < 0) { - throw new IllegalArgumentException("maxCapacity: " + maxCapacity + " (expected: >= 0)"); - } - this.maxCapacity = maxCapacity; - } - - @Override - public final BufType type() { - return BufType.MESSAGE; - } - - @Override - public final int refCnt() { - if (REFCNT_FIELD_OFFSET >= 0) { - // Try to do non-volatile read for performance. - return PlatformDependent.getInt(this, REFCNT_FIELD_OFFSET); - } else { - return refCnt; - } - } - - @Override - public MessageBuf retain() { - for (;;) { - int refCnt = this.refCnt; - if (refCnt == 0) { - throw new IllegalBufferAccessException(); - } - if (refCnt == Integer.MAX_VALUE) { - throw new IllegalBufferAccessException("refCnt overflow"); - } - if (refCntUpdater.compareAndSet(this, refCnt, refCnt + 1)) { - break; - } - } - return this; - } - - @Override - public MessageBuf retain(int increment) { - if (increment <= 0) { - throw new IllegalArgumentException("increment: " + increment + " (expected: > 0)"); - } - - for (;;) { - int refCnt = this.refCnt; - if (refCnt == 0) { - throw new IllegalBufferAccessException(); - } - if (refCnt > Integer.MAX_VALUE - increment) { - throw new IllegalBufferAccessException("refCnt overflow"); - } - if (refCntUpdater.compareAndSet(this, refCnt, refCnt + increment)) { - break; - } - } - return this; - } - - @Override - public final boolean release() { - for (;;) { - int refCnt = this.refCnt; - if (refCnt == 0) { - throw new IllegalBufferAccessException(); - } - - if (refCntUpdater.compareAndSet(this, refCnt, refCnt - 1)) { - if (refCnt == 1) { - deallocate(); - return true; - } - return false; - } - } - } - - @Override - public final boolean release(int decrement) { - if (decrement <= 0) { - throw new IllegalArgumentException("decrement: " + decrement + " (expected: > 0)"); - } - - for (;;) { - int refCnt = this.refCnt; - if (refCnt < decrement) { - throw new IllegalBufferAccessException(); - } - - if (refCntUpdater.compareAndSet(this, refCnt, refCnt - decrement)) { - if (refCnt == decrement) { - deallocate(); - return true; - } - return false; - } - } - } - - protected abstract void deallocate(); - - @Override - public final int maxCapacity() { - return maxCapacity; - } - - @Override - public final boolean isReadable() { - return !isEmpty(); - } - - @Override - public final boolean isReadable(int size) { - if (size < 0) { - throw new IllegalArgumentException("size: " + size + " (expected: >= 0)"); - } - return size() >= size; - } - - @Override - public final boolean isWritable() { - return size() < maxCapacity; - } - - @Override - public final boolean isWritable(int size) { - if (size < 0) { - throw new IllegalArgumentException("size: " + size + " (expected: >= 0)"); - } - return size() <= maxCapacity - size; - } - - protected final void ensureAccessible() { - if (refCnt <= 0) { - throw new IllegalBufferAccessException(); - } - } - - @Override - public final boolean add(T t) { - return super.add(t); - } - - @Override - public final T remove() { - return super.remove(); - } - - @Override - public final T element() { - return super.element(); - } - - @Override - public int drainTo(Collection c) { - ensureAccessible(); - int cnt = 0; - for (;;) { - T o = poll(); - if (o == null) { - break; - } - c.add(o); - cnt ++; - } - return cnt; - } - - @Override - public int drainTo(Collection c, int maxElements) { - ensureAccessible(); - int cnt = 0; - while (cnt < maxElements) { - T o = poll(); - if (o == null) { - break; - } - c.add(o); - cnt ++; - } - return cnt; - } - - @Override - public String toString() { - if (refCnt <= 0) { - return getClass().getSimpleName() + "(freed)"; - } - - StringBuilder buf = new StringBuilder(); - buf.append(getClass().getSimpleName()); - buf.append("(size: "); - buf.append(size()); - if (maxCapacity != Integer.MAX_VALUE) { - buf.append('/'); - buf.append(maxCapacity); - } - buf.append(')'); - - return buf.toString(); - } -} diff --git a/buffer/src/main/java/io/netty/buffer/Buf.java b/buffer/src/main/java/io/netty/buffer/Buf.java deleted file mode 100644 index 5cf36606e7..0000000000 --- a/buffer/src/main/java/io/netty/buffer/Buf.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright 2012 The Netty Project - * - * The Netty Project licenses this file to you under the Apache License, - * version 2.0 (the "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. - */ -package io.netty.buffer; - -/** - * A buffer to operate on - */ -public interface Buf extends ReferenceCounted { - /** - * The BufType which will be handled by the Buf implementation - */ - BufType type(); - - /** - * Returns the maximum allowed capacity of this buffer. - */ - int maxCapacity(); - - /** - * Returns {@code true} if and only if this buffer contains at least one readable element. - */ - boolean isReadable(); - - /** - * Returns {@code true} if and only if this buffer contains equal to or more than the specified number of elements. - */ - boolean isReadable(int size); - - /** - * Returns {@code true} if and only if this buffer has enough room to allow writing one element. - */ - boolean isWritable(); - - /** - * Returns {@code true} if and only if this buffer has enough room to allow writing the specified number of - * elements. - */ - boolean isWritable(int size); - - @Override - Buf retain(); - - @Override - Buf retain(int increment); -} diff --git a/buffer/src/main/java/io/netty/buffer/ByteBuf.java b/buffer/src/main/java/io/netty/buffer/ByteBuf.java index ce0c68ea71..b201d26328 100644 --- a/buffer/src/main/java/io/netty/buffer/ByteBuf.java +++ b/buffer/src/main/java/io/netty/buffer/ByteBuf.java @@ -227,7 +227,7 @@ import java.nio.charset.UnsupportedCharsetException; * Please refer to {@link ByteBufInputStream} and * {@link ByteBufOutputStream}. */ -public interface ByteBuf extends Buf, Comparable { +public interface ByteBuf extends ReferenceCounted, Comparable { /** * Returns the number of bytes (octets) this buffer can contain. @@ -248,7 +248,6 @@ public interface ByteBuf extends Buf, Comparable { * {@link #ensureWritable(int)}, those methods will raise an * {@link IllegalArgumentException}. */ - @Override int maxCapacity(); /** @@ -391,9 +390,13 @@ public interface ByteBuf extends Buf, Comparable { * if and only if {@code (this.writerIndex - this.readerIndex)} is greater * than {@code 0}. */ - @Override boolean isReadable(); + /** + * Returns {@code true} if and only if this buffer contains equal to or more than the specified number of elements. + */ + boolean isReadable(int size); + /** * @deprecated Use {@link #isReadable()} or {@link #isReadable(int)} instead. */ @@ -405,9 +408,14 @@ public interface ByteBuf extends Buf, Comparable { * if and only if {@code (this.capacity - this.writerIndex)} is greater * than {@code 0}. */ - @Override boolean isWritable(); + /** + * Returns {@code true} if and only if this buffer has enough room to allow writing the specified number of + * elements. + */ + boolean isWritable(int size); + /** * @deprecated Use {@link #isWritable()} or {@link #isWritable(int)} instead. */ @@ -1869,23 +1877,6 @@ public interface ByteBuf extends Buf, Comparable { */ String toString(int index, int length, Charset charset); - /** - * Suspends the intermediary deallocation of the internal memory block of this buffer until asked via - * {@link #resumeIntermediaryDeallocations()}. An intermediary deallocation is usually made when the capacity of - * a buffer changes. - * - * @throws UnsupportedOperationException if this buffer is derived - */ - ByteBuf suspendIntermediaryDeallocations(); - - /** - * Resumes the intermediary deallocation of the internal memory block of this buffer, suspended by - * {@link #suspendIntermediaryDeallocations()}. - * - * @throws UnsupportedOperationException if this buffer is derived - */ - ByteBuf resumeIntermediaryDeallocations(); - /** * Returns a hash code which was calculated from the content of this * buffer. If there's a byte array which is diff --git a/buffer/src/main/java/io/netty/buffer/BufUtil.java b/buffer/src/main/java/io/netty/buffer/ByteBufUtil.java similarity index 94% rename from buffer/src/main/java/io/netty/buffer/BufUtil.java rename to buffer/src/main/java/io/netty/buffer/ByteBufUtil.java index b651316387..323b26ed25 100644 --- a/buffer/src/main/java/io/netty/buffer/BufUtil.java +++ b/buffer/src/main/java/io/netty/buffer/ByteBufUtil.java @@ -25,13 +25,11 @@ import java.nio.charset.Charset; import java.nio.charset.CharsetDecoder; import java.nio.charset.CharsetEncoder; import java.nio.charset.CoderResult; -import java.util.Iterator; /** - * A collection of utility methods that is related with handling {@link ByteBuf}, {@link MessageBuf}, and their - * elements. + * A collection of utility methods that is related with handling {@link ByteBuf}. */ -public final class BufUtil { +public final class ByteBufUtil { private static final char[] HEXDUMP_TABLE = new char[256 * 4]; @@ -418,29 +416,5 @@ public final class BufUtil { return dst.flip().toString(); } - /** - * Return the content of the given {@link MessageBuf} as string representation. - */ - public static String contentToString(MessageBuf buf) { - if (buf.isEmpty()) { - return "[]"; - } - Iterator it = buf.iterator(); - StringBuilder sb = new StringBuilder(); - sb.append('['); - while (it.hasNext()) { - Object msg = it.next(); - if (msg == buf) { - sb.append('(' + buf.getClass().getSimpleName() + ')'); - } else { - sb.append(msg); - } - if (it.hasNext()) { - sb.append(", "); - } - } - return sb.append(']').toString(); - } - - private BufUtil() { } + private ByteBufUtil() { } } diff --git a/buffer/src/main/java/io/netty/buffer/CompositeByteBuf.java b/buffer/src/main/java/io/netty/buffer/CompositeByteBuf.java index 483390bd33..f39a50608f 100644 --- a/buffer/src/main/java/io/netty/buffer/CompositeByteBuf.java +++ b/buffer/src/main/java/io/netty/buffer/CompositeByteBuf.java @@ -387,12 +387,6 @@ public interface CompositeByteBuf extends ByteBuf, Iterable { @Override CompositeByteBuf writeZero(int length); - @Override - CompositeByteBuf suspendIntermediaryDeallocations(); - - @Override - CompositeByteBuf resumeIntermediaryDeallocations(); - @Override CompositeByteBuf retain(int increment); diff --git a/buffer/src/main/java/io/netty/buffer/DefaultCompositeByteBuf.java b/buffer/src/main/java/io/netty/buffer/DefaultCompositeByteBuf.java index 49dc661d29..9dfd3ddf0e 100644 --- a/buffer/src/main/java/io/netty/buffer/DefaultCompositeByteBuf.java +++ b/buffer/src/main/java/io/netty/buffer/DefaultCompositeByteBuf.java @@ -26,14 +26,12 @@ import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.nio.channels.GatheringByteChannel; import java.nio.channels.ScatteringByteChannel; -import java.util.ArrayDeque; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Iterator; import java.util.List; import java.util.ListIterator; -import java.util.Queue; /** @@ -50,7 +48,6 @@ public class DefaultCompositeByteBuf extends AbstractReferenceCountedByteBuf imp private final int maxNumComponents; private boolean freed; - private Queue suspendedDeallocations; public DefaultCompositeByteBuf(ByteBufAllocator alloc, boolean direct, int maxNumComponents) { super(Integer.MAX_VALUE); @@ -1202,11 +1199,7 @@ public class DefaultCompositeByteBuf extends AbstractReferenceCountedByteBuf imp void freeIfNecessary() { // Unwrap so that we can free slices, too. - if (suspendedDeallocations == null) { - buf.release(); // We should not get a NPE here. If so, it must be a bug. - } else { - suspendedDeallocations.add(buf); - } + buf.release(); // We should not get a NPE here. If so, it must be a bug. } } @@ -1457,7 +1450,6 @@ public class DefaultCompositeByteBuf extends AbstractReferenceCountedByteBuf imp } freed = true; - resumeIntermediaryDeallocations(); for (Component c: components) { c.freeIfNecessary(); } @@ -1465,30 +1457,6 @@ public class DefaultCompositeByteBuf extends AbstractReferenceCountedByteBuf imp leak.close(); } - @Override - public CompositeByteBuf suspendIntermediaryDeallocations() { - ensureAccessible(); - if (suspendedDeallocations == null) { - suspendedDeallocations = new ArrayDeque(2); - } - return this; - } - - @Override - public CompositeByteBuf resumeIntermediaryDeallocations() { - if (suspendedDeallocations == null) { - return this; - } - - Queue suspendedDeallocations = this.suspendedDeallocations; - this.suspendedDeallocations = null; - - for (ByteBuf buf: suspendedDeallocations) { - buf.release(); - } - return this; - } - @Override public ByteBuf unwrap() { return null; diff --git a/buffer/src/main/java/io/netty/buffer/DefaultMessageBuf.java b/buffer/src/main/java/io/netty/buffer/DefaultMessageBuf.java deleted file mode 100644 index 300b3d46b1..0000000000 --- a/buffer/src/main/java/io/netty/buffer/DefaultMessageBuf.java +++ /dev/null @@ -1,337 +0,0 @@ -/* - * Copyright 2012 The Netty Project - * - * The Netty Project licenses this file to you under the Apache License, - * version 2.0 (the "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. - */ -/* - * Written by Josh Bloch of Google Inc. and released to the public domain, - * as explained at http://creativecommons.org/publicdomain/zero/1.0/. - */ -package io.netty.buffer; - -import java.lang.reflect.Array; -import java.util.ConcurrentModificationException; -import java.util.Iterator; -import java.util.NoSuchElementException; - -/** - * Default {@link MessageBuf} implementation. - * - * You should use {@link Unpooled#messageBuffer()} to create an instance - * - */ -public class DefaultMessageBuf extends AbstractMessageBuf { - - private static final int MIN_INITIAL_CAPACITY = 8; - private static final Object[] PLACEHOLDER = new Object[2]; - - private T[] elements; - private int head; - private int tail; - - protected DefaultMessageBuf() { - this(MIN_INITIAL_CAPACITY << 1); - } - - protected DefaultMessageBuf(int initialCapacity) { - this(initialCapacity, Integer.MAX_VALUE); - } - - protected DefaultMessageBuf(int initialCapacity, int maxCapacity) { - super(maxCapacity); - - if (initialCapacity < 0) { - throw new IllegalArgumentException("initialCapacity: " + initialCapacity + " (expected: >= 0)"); - } - if (maxCapacity < initialCapacity) { - throw new IllegalArgumentException( - "maxCapacity: " + maxCapacity + " (expected: >= initialCapacity(" + initialCapacity + ')'); - } - - // Find the best power of two to hold elements. - // Tests "<=" because arrays aren't kept full. - if (initialCapacity >= MIN_INITIAL_CAPACITY) { - initialCapacity |= initialCapacity >>> 1; - initialCapacity |= initialCapacity >>> 2; - initialCapacity |= initialCapacity >>> 4; - initialCapacity |= initialCapacity >>> 8; - initialCapacity |= initialCapacity >>> 16; - initialCapacity ++; - - if (initialCapacity < 0) { // Too many elements, must back off - initialCapacity >>>= 1; // Good luck allocating 2 ^ 30 elements - } - } else { - initialCapacity = MIN_INITIAL_CAPACITY; - } - - elements = cast(new Object[initialCapacity]); - } - - @Override - protected void deallocate() { - head = 0; - tail = 0; - elements = cast(PLACEHOLDER); - } - - @Override - public boolean offer(T e) { - if (e == null) { - throw new NullPointerException(); - } - - ensureAccessible(); - if (!isWritable()) { - return false; - } - - elements[tail] = e; - if ((tail = tail + 1 & elements.length - 1) == head) { - doubleCapacity(); - } - - return true; - } - - private void doubleCapacity() { - assert head == tail; - - int p = head; - int n = elements.length; - int r = n - p; // number of elements to the right of p - int newCapacity = n << 1; - if (newCapacity < 0) { - throw new IllegalStateException("Sorry, deque too big"); - } - Object[] a = new Object[newCapacity]; - System.arraycopy(elements, p, a, 0, r); - System.arraycopy(elements, 0, a, r, p); - elements = cast(a); - head = 0; - tail = n; - } - - @Override - public T poll() { - ensureAccessible(); - int h = head; - T result = elements[h]; // Element is null if deque empty - if (result == null) { - return null; - } - elements[h] = null; // Must null out slot - head = h + 1 & elements.length - 1; - return result; - } - - @Override - public T peek() { - ensureAccessible(); - return elements[head]; // elements[head] is null if deque empty - } - - @Override - public boolean remove(Object o) { - if (o == null) { - return false; - } - - ensureAccessible(); - int mask = elements.length - 1; - int i = head; - T x; - while ((x = elements[i]) != null) { - if (o.equals(x)) { - delete(i); - return true; - } - i = i + 1 & mask; - } - return false; - } - - private boolean delete(int i) { - assert elements[tail] == null; - assert head == tail ? elements[head] == null - : elements[head] != null && elements[tail - 1 & elements.length - 1] != null; - assert elements[head - 1 & elements.length - 1] == null; - - final T[] elements = this.elements; - final int mask = elements.length - 1; - final int h = head; - final int t = tail; - final int front = i - h & mask; - final int back = t - i & mask; - - // Invariant: head <= i < tail mod circularity - if (front >= (t - h & mask)) { - throw new ConcurrentModificationException(); - } - - // Optimize for least element motion - if (front < back) { - if (h <= i) { - System.arraycopy(elements, h, elements, h + 1, front); - } else { // Wrap around - System.arraycopy(elements, 0, elements, 1, i); - elements[0] = elements[mask]; - System.arraycopy(elements, h, elements, h + 1, mask - h); - } - elements[h] = null; - head = h + 1 & mask; - return false; - } else { - if (i < t) { // Copy the null tail as well - System.arraycopy(elements, i + 1, elements, i, back); - tail = t - 1; - } else { // Wrap around - System.arraycopy(elements, i + 1, elements, i, mask - i); - elements[mask] = elements[0]; - System.arraycopy(elements, 1, elements, 0, t); - tail = t - 1 & mask; - } - return true; - } - } - - @Override - public int size() { - return tail - head & elements.length - 1; - } - - @Override - public boolean isEmpty() { - return head == tail; - } - - @Override - public Iterator iterator() { - ensureAccessible(); - return new Itr(); - } - - @Override - public boolean contains(Object o) { - if (o == null) { - return false; - } - - ensureAccessible(); - final int mask = elements.length - 1; - int i = head; - Object e; - while ((e = elements[i]) != null) { - if (o.equals(e)) { - return true; - } - i = i + 1 & mask; - } - - return false; - } - - @Override - public void clear() { - ensureAccessible(); - int head = this.head; - int tail = this.tail; - if (head != tail) { - this.head = this.tail = 0; - final int mask = elements.length - 1; - int i = head; - do { - elements[i] = null; - i = i + 1 & mask; - } while (i != tail); - } - } - - @Override - public Object[] toArray() { - ensureAccessible(); - return copyElements(new Object[size()]); - } - - @Override - public T[] toArray(T[] a) { - ensureAccessible(); - int size = size(); - if (a.length < size) { - a = cast(Array.newInstance(a.getClass().getComponentType(), size)); - } - copyElements(a); - if (a.length > size) { - a[size] = null; - } - return a; - } - - private U[] copyElements(U[] a) { - if (head < tail) { - System.arraycopy(elements, head, cast(a), 0, size()); - } else if (head > tail) { - int headPortionLen = elements.length - head; - System.arraycopy(elements, head, cast(a), 0, headPortionLen); - System.arraycopy(elements, 0, cast(a), headPortionLen, tail); - } - return a; - } - - @SuppressWarnings({ "unchecked", "SuspiciousArrayCast" }) - private static T[] cast(Object a) { - return (T[]) a; - } - - private class Itr implements Iterator { - private int cursor = head; - private int fence = tail; - private int lastRet = -1; - - @Override - public boolean hasNext() { - ensureAccessible(); - return cursor != fence; - } - - @Override - public T next() { - ensureAccessible(); - if (cursor == fence) { - throw new NoSuchElementException(); - } - T result = elements[cursor]; - // This check doesn't catch all possible comodifications, - // but does catch the ones that corrupt traversal - if (tail != fence || result == null) { - throw new ConcurrentModificationException(); - } - lastRet = cursor; - cursor = cursor + 1 & elements.length - 1; - return result; - } - - @Override - public void remove() { - ensureAccessible(); - if (lastRet < 0) { - throw new IllegalStateException(); - } - if (delete(lastRet)) { // if left-shifted, undo increment in next() - cursor = cursor - 1 & elements.length - 1; - fence = tail; - } - lastRet = -1; - } - } -} diff --git a/buffer/src/main/java/io/netty/buffer/EmptyByteBuf.java b/buffer/src/main/java/io/netty/buffer/EmptyByteBuf.java index 07745ec127..dcf152508d 100644 --- a/buffer/src/main/java/io/netty/buffer/EmptyByteBuf.java +++ b/buffer/src/main/java/io/netty/buffer/EmptyByteBuf.java @@ -800,16 +800,6 @@ public final class EmptyByteBuf implements ByteBuf { return toString(charset); } - @Override - public ByteBuf suspendIntermediaryDeallocations() { - return this; - } - - @Override - public ByteBuf resumeIntermediaryDeallocations() { - return this; - } - @Override public int hashCode() { return 0; @@ -830,11 +820,6 @@ public final class EmptyByteBuf implements ByteBuf { return str; } - @Override - public BufType type() { - return BufType.BYTE; - } - @Override public boolean isReadable(int size) { checkLength(size); diff --git a/buffer/src/main/java/io/netty/buffer/FilteredMessageBuf.java b/buffer/src/main/java/io/netty/buffer/FilteredMessageBuf.java deleted file mode 100644 index 496814db08..0000000000 --- a/buffer/src/main/java/io/netty/buffer/FilteredMessageBuf.java +++ /dev/null @@ -1,229 +0,0 @@ -/* - * Copyright 2013 The Netty Project - * - * The Netty Project licenses this file to you under the Apache License, - * version 2.0 (the "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. - */ - -package io.netty.buffer; - -import java.util.Collection; -import java.util.Iterator; - -public abstract class FilteredMessageBuf implements MessageBuf { - - protected final MessageBuf buf; - - @SuppressWarnings("unchecked") - protected FilteredMessageBuf(MessageBuf buf) { - if (buf == null) { - throw new NullPointerException("buf"); - } - this.buf = (MessageBuf) buf; - } - - protected abstract Object filter(Object msg); - - @Override - public int drainTo(Collection c) { - return buf.drainTo(c); - } - - @Override - public int drainTo(Collection c, int maxElements) { - return buf.drainTo(c, maxElements); - } - - @Override - public BufType type() { - return buf.type(); - } - - @Override - public int maxCapacity() { - return buf.maxCapacity(); - } - - @Override - public boolean isReadable() { - return buf.isReadable(); - } - - @Override - public boolean isReadable(int size) { - return buf.isReadable(size); - } - - @Override - public boolean isWritable() { - return buf.isWritable(); - } - - @Override - public boolean isWritable(int size) { - return buf.isWritable(size); - } - - @Override - public boolean add(Object e) { - if (e == null) { - throw new NullPointerException("e"); - } - - e = filter(e); - ensureNonNull(e); - - return buf.add(e); - } - - @Override - public boolean offer(Object e) { - if (e == null) { - throw new NullPointerException("e"); - } - - e = filter(e); - ensureNonNull(e); - - return buf.offer(e); - } - - private void ensureNonNull(Object e) { - if (e == null) { - throw new IllegalStateException(getClass().getSimpleName() + ".filter() returned null"); - } - } - - @Override - public Object remove() { - return buf.remove(); - } - - @Override - public Object poll() { - return buf.poll(); - } - - @Override - public Object element() { - return buf.element(); - } - - @Override - public Object peek() { - return buf.peek(); - } - - @Override - public int size() { - return buf.size(); - } - - @Override - public boolean isEmpty() { - return buf.isEmpty(); - } - - @Override - public boolean contains(Object o) { - return buf.contains(o); - } - - @Override - public Iterator iterator() { - return buf.iterator(); - } - - @Override - public Object[] toArray() { - return buf.toArray(); - } - - @Override - public T[] toArray(T[] a) { - return buf.toArray(a); - } - - @Override - public boolean remove(Object o) { - return buf.remove(o); - } - - @Override - public boolean containsAll(Collection c) { - return buf.containsAll(c); - } - - @Override - public boolean addAll(Collection c) { - int i = 0; - boolean added = false; - for (Object e: c) { - if (e == null) { - throw new NullPointerException("c[" + i + ']'); - } - - e = filter(e); - ensureNonNull(e); - added |= buf.add(e); - } - return added; - } - - @Override - public boolean removeAll(Collection c) { - return buf.removeAll(c); - } - - @Override - public boolean retainAll(Collection c) { - return buf.retainAll(c); - } - - @Override - public void clear() { - buf.clear(); - } - - @Override - public int refCnt() { - return buf.refCnt(); - } - - @Override - public MessageBuf retain() { - buf.retain(); - return this; - } - - @Override - public MessageBuf retain(int increment) { - buf.retain(increment); - return this; - } - - @Override - public boolean release() { - return buf.release(); - } - - @Override - public boolean release(int decrement) { - return buf.release(decrement); - } - - @Override - public String toString() { - return getClass().getSimpleName() + '(' + buf + ')'; - } -} - diff --git a/buffer/src/main/java/io/netty/buffer/MessageBuf.java b/buffer/src/main/java/io/netty/buffer/MessageBuf.java deleted file mode 100644 index e5d47df8e7..0000000000 --- a/buffer/src/main/java/io/netty/buffer/MessageBuf.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright 2012 The Netty Project - * - * The Netty Project licenses this file to you under the Apache License, - * version 2.0 (the "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. - */ -package io.netty.buffer; - -import java.util.Collection; -import java.util.Queue; - -/** - * Buf which operates on messages. - * - * @param the type of the messages that are hold by this {@link MessageBuf} - */ -public interface MessageBuf extends Buf, Queue { - - /** - * Drain the content of the {@link MessageBuf} to the given {@link Collection}. - * - * @param c the {@link Collection} to drain the content to - * @return number the number of objects which was transfered - */ - int drainTo(Collection c); - - /** - * Drain the content of the {@link MessageBuf} to the given {@link Collection}. - * - * @param c the {@link Collection} to drain the content to - * @param maxElements the max number of elements to drain - * @return number the number of objects which was transfered - */ - int drainTo(Collection c, int maxElements); - - @Override - MessageBuf retain(int increment); - - @Override - MessageBuf retain(); -} diff --git a/buffer/src/main/java/io/netty/buffer/PooledByteBuf.java b/buffer/src/main/java/io/netty/buffer/PooledByteBuf.java index 1e67c88c44..153c3475c9 100644 --- a/buffer/src/main/java/io/netty/buffer/PooledByteBuf.java +++ b/buffer/src/main/java/io/netty/buffer/PooledByteBuf.java @@ -20,8 +20,6 @@ import io.netty.util.ResourceLeak; import java.nio.ByteBuffer; import java.nio.ByteOrder; -import java.util.ArrayDeque; -import java.util.Queue; abstract class PooledByteBuf extends AbstractReferenceCountedByteBuf { @@ -35,7 +33,6 @@ abstract class PooledByteBuf extends AbstractReferenceCountedByteBuf { private int maxLength; private ByteBuffer tmpNioBuf; - private Queue> suspendedDeallocations; protected PooledByteBuf(int maxCapacity) { super(maxCapacity); @@ -108,13 +105,7 @@ abstract class PooledByteBuf extends AbstractReferenceCountedByteBuf { } // Reallocation required. - if (suspendedDeallocations == null) { - chunk.arena.reallocate(this, newCapacity, true); - } else { - Allocation old = new Allocation(chunk, handle); - chunk.arena.reallocate(this, newCapacity, false); - suspendedDeallocations.add(old); - } + chunk.arena.reallocate(this, newCapacity, true); return this; } @@ -143,38 +134,9 @@ abstract class PooledByteBuf extends AbstractReferenceCountedByteBuf { protected abstract ByteBuffer newInternalNioBuffer(T memory); - @Override - public final ByteBuf suspendIntermediaryDeallocations() { - ensureAccessible(); - if (suspendedDeallocations == null) { - suspendedDeallocations = new ArrayDeque>(2); - } - return this; - } - - @Override - public final ByteBuf resumeIntermediaryDeallocations() { - if (suspendedDeallocations == null) { - return this; - } - - Queue> suspendedDeallocations = this.suspendedDeallocations; - this.suspendedDeallocations = null; - - if (suspendedDeallocations.isEmpty()) { - return this; - } - - for (Allocation a: suspendedDeallocations) { - a.chunk.arena.free(a.chunk, a.handle); - } - return this; - } - @Override protected final void deallocate() { if (handle >= 0) { - resumeIntermediaryDeallocations(); final long handle = this.handle; this.handle = -1; memory = null; @@ -186,14 +148,4 @@ abstract class PooledByteBuf extends AbstractReferenceCountedByteBuf { protected final int idx(int index) { return offset + index; } - - private static final class Allocation { - final PoolChunk chunk; - final long handle; - - Allocation(PoolChunk chunk, long handle) { - this.chunk = chunk; - this.handle = handle; - } - } } diff --git a/buffer/src/main/java/io/netty/buffer/QueueBackedMessageBuf.java b/buffer/src/main/java/io/netty/buffer/QueueBackedMessageBuf.java deleted file mode 100644 index 6c193c2a3d..0000000000 --- a/buffer/src/main/java/io/netty/buffer/QueueBackedMessageBuf.java +++ /dev/null @@ -1,132 +0,0 @@ -/* - * Copyright 2012 The Netty Project - * - * The Netty Project licenses this file to you under the Apache License, - * version 2.0 (the "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. - */ -package io.netty.buffer; - -import java.util.Collection; -import java.util.Iterator; -import java.util.Queue; - -final class QueueBackedMessageBuf extends AbstractMessageBuf { - - private Queue queue; - - QueueBackedMessageBuf(Queue queue) { - super(Integer.MAX_VALUE); - if (queue == null) { - throw new NullPointerException("queue"); - } - this.queue = queue; - } - - @Override - public boolean offer(T e) { - if (e == null) { - throw new NullPointerException("e"); - } - ensureAccessible(); - return isWritable() && queue.offer(e); - } - - @Override - public T poll() { - ensureAccessible(); - return queue.poll(); - } - - @Override - public T peek() { - ensureAccessible(); - return queue.peek(); - } - - @Override - public int size() { - return queue.size(); - } - - @Override - public boolean isEmpty() { - return queue.isEmpty(); - } - - @Override - public boolean contains(Object o) { - ensureAccessible(); - return queue.contains(o); - } - - @Override - public Iterator iterator() { - ensureAccessible(); - return queue.iterator(); - } - - @Override - public Object[] toArray() { - ensureAccessible(); - return queue.toArray(); - } - - @Override - public E[] toArray(E[] a) { - ensureAccessible(); - return queue.toArray(a); - } - - @Override - public boolean remove(Object o) { - ensureAccessible(); - return queue.remove(o); - } - - @Override - public boolean containsAll(Collection c) { - ensureAccessible(); - return queue.containsAll(c); - } - - @Override - public boolean addAll(Collection c) { - ensureAccessible(); - return isWritable(c.size()) && queue.addAll(c); - } - - @Override - public boolean removeAll(Collection c) { - ensureAccessible(); - return queue.removeAll(c); - } - - @Override - public boolean retainAll(Collection c) { - ensureAccessible(); - return queue.retainAll(c); - } - - @Override - public void clear() { - ensureAccessible(); - queue.clear(); - } - - @Override - protected void deallocate() { - for (T e: queue) { - BufUtil.release(e); - } - queue = null; - } -} diff --git a/buffer/src/main/java/io/netty/buffer/ReadOnlyByteBufferBuf.java b/buffer/src/main/java/io/netty/buffer/ReadOnlyByteBufferBuf.java index dd5345d63f..83b72bea46 100644 --- a/buffer/src/main/java/io/netty/buffer/ReadOnlyByteBufferBuf.java +++ b/buffer/src/main/java/io/netty/buffer/ReadOnlyByteBufferBuf.java @@ -316,14 +316,4 @@ class ReadOnlyByteBufferBuf extends AbstractReferenceCountedByteBuf { public long memoryAddress() { throw new UnsupportedOperationException(); } - - @Override - public ByteBuf suspendIntermediaryDeallocations() { - return this; - } - - @Override - public ByteBuf resumeIntermediaryDeallocations() { - return this; - } } diff --git a/buffer/src/main/java/io/netty/buffer/SwappedByteBuf.java b/buffer/src/main/java/io/netty/buffer/SwappedByteBuf.java index a18c4dc1e4..566e0b38b0 100644 --- a/buffer/src/main/java/io/netty/buffer/SwappedByteBuf.java +++ b/buffer/src/main/java/io/netty/buffer/SwappedByteBuf.java @@ -67,11 +67,6 @@ public final class SwappedByteBuf implements ByteBuf { return buf.alloc(); } - @Override - public BufType type() { - return BufType.MESSAGE; - } - @Override public int capacity() { return buf.capacity(); @@ -245,7 +240,7 @@ public final class SwappedByteBuf implements ByteBuf { @Override public short getShort(int index) { - return BufUtil.swapShort(buf.getShort(index)); + return ByteBufUtil.swapShort(buf.getShort(index)); } @Override @@ -255,7 +250,7 @@ public final class SwappedByteBuf implements ByteBuf { @Override public int getMedium(int index) { - return BufUtil.swapMedium(buf.getMedium(index)); + return ByteBufUtil.swapMedium(buf.getMedium(index)); } @Override @@ -265,7 +260,7 @@ public final class SwappedByteBuf implements ByteBuf { @Override public int getInt(int index) { - return BufUtil.swapInt(buf.getInt(index)); + return ByteBufUtil.swapInt(buf.getInt(index)); } @Override @@ -275,7 +270,7 @@ public final class SwappedByteBuf implements ByteBuf { @Override public long getLong(int index) { - return BufUtil.swapLong(buf.getLong(index)); + return ByteBufUtil.swapLong(buf.getLong(index)); } @Override @@ -354,25 +349,25 @@ public final class SwappedByteBuf implements ByteBuf { @Override public ByteBuf setShort(int index, int value) { - buf.setShort(index, BufUtil.swapShort((short) value)); + buf.setShort(index, ByteBufUtil.swapShort((short) value)); return this; } @Override public ByteBuf setMedium(int index, int value) { - buf.setMedium(index, BufUtil.swapMedium(value)); + buf.setMedium(index, ByteBufUtil.swapMedium(value)); return this; } @Override public ByteBuf setInt(int index, int value) { - buf.setInt(index, BufUtil.swapInt(value)); + buf.setInt(index, ByteBufUtil.swapInt(value)); return this; } @Override public ByteBuf setLong(int index, long value) { - buf.setLong(index, BufUtil.swapLong(value)); + buf.setLong(index, ByteBufUtil.swapLong(value)); return this; } @@ -463,7 +458,7 @@ public final class SwappedByteBuf implements ByteBuf { @Override public short readShort() { - return BufUtil.swapShort(buf.readShort()); + return ByteBufUtil.swapShort(buf.readShort()); } @Override @@ -473,7 +468,7 @@ public final class SwappedByteBuf implements ByteBuf { @Override public int readMedium() { - return BufUtil.swapMedium(buf.readMedium()); + return ByteBufUtil.swapMedium(buf.readMedium()); } @Override @@ -483,7 +478,7 @@ public final class SwappedByteBuf implements ByteBuf { @Override public int readInt() { - return BufUtil.swapInt(buf.readInt()); + return ByteBufUtil.swapInt(buf.readInt()); } @Override @@ -493,7 +488,7 @@ public final class SwappedByteBuf implements ByteBuf { @Override public long readLong() { - return BufUtil.swapLong(buf.readLong()); + return ByteBufUtil.swapLong(buf.readLong()); } @Override @@ -588,25 +583,25 @@ public final class SwappedByteBuf implements ByteBuf { @Override public ByteBuf writeShort(int value) { - buf.writeShort(BufUtil.swapShort((short) value)); + buf.writeShort(ByteBufUtil.swapShort((short) value)); return this; } @Override public ByteBuf writeMedium(int value) { - buf.writeMedium(BufUtil.swapMedium(value)); + buf.writeMedium(ByteBufUtil.swapMedium(value)); return this; } @Override public ByteBuf writeInt(int value) { - buf.writeInt(BufUtil.swapInt(value)); + buf.writeInt(ByteBufUtil.swapInt(value)); return this; } @Override public ByteBuf writeLong(long value) { - buf.writeLong(BufUtil.swapLong(value)); + buf.writeLong(ByteBufUtil.swapLong(value)); return this; } @@ -813,18 +808,6 @@ public final class SwappedByteBuf implements ByteBuf { return buf.toString(index, length, charset); } - @Override - public ByteBuf suspendIntermediaryDeallocations() { - buf.suspendIntermediaryDeallocations(); - return this; - } - - @Override - public ByteBuf resumeIntermediaryDeallocations() { - buf.resumeIntermediaryDeallocations(); - return this; - } - @Override public int refCnt() { return buf.refCnt(); @@ -863,14 +846,14 @@ public final class SwappedByteBuf implements ByteBuf { return true; } if (obj instanceof ByteBuf) { - return BufUtil.equals(this, (ByteBuf) obj); + return ByteBufUtil.equals(this, (ByteBuf) obj); } return false; } @Override public int compareTo(ByteBuf buffer) { - return BufUtil.compare(this, buffer); + return ByteBufUtil.compare(this, buffer); } @Override diff --git a/buffer/src/main/java/io/netty/buffer/Unpooled.java b/buffer/src/main/java/io/netty/buffer/Unpooled.java index 92ae8d2186..46fce0fc3a 100644 --- a/buffer/src/main/java/io/netty/buffer/Unpooled.java +++ b/buffer/src/main/java/io/netty/buffer/Unpooled.java @@ -23,11 +23,10 @@ import java.nio.CharBuffer; import java.nio.charset.Charset; import java.util.ArrayList; import java.util.List; -import java.util.Queue; /** - * Creates a new {@link ByteBuf} or a new {@link MessageBuf} by allocating new space or by wrapping + * Creates a new {@link ByteBuf} by allocating new space or by wrapping * or copying existing byte arrays, byte buffers and a string. * *

Use static import

@@ -94,39 +93,6 @@ public final class Unpooled { */ public static final ByteBuf EMPTY_BUFFER = ALLOC.buffer(0, 0); - /** - * Creates a new {@link MessageBuf} with reasonably small initial capacity, which - * expands its capacity boundlessly on demand. - */ - public static MessageBuf messageBuffer() { - return new DefaultMessageBuf(); - } - - /** - * Creates a new {@link MessageBuf} with the specified {@code initialCapacity}. - */ - public static MessageBuf messageBuffer(int initialCapacity) { - return new DefaultMessageBuf(initialCapacity); - } - - /** - * Creates a new {@link MessageBuf} with the specified {@code initialCapacity} and - * {@code maxCapacity}. - */ - public static MessageBuf messageBuffer(int initialCapacity, int maxCapacity) { - return new DefaultMessageBuf(initialCapacity, maxCapacity); - } - - /** - * Creates a new {@link MessageBuf} which wraps the given {@code queue}. - */ - public static MessageBuf wrappedBuffer(Queue queue) { - if (queue instanceof MessageBuf) { - return (MessageBuf) queue; - } - return new QueueBackedMessageBuf(queue); - } - /** * Creates a new big-endian Java heap buffer with reasonably small initial capacity, which * expands its capacity boundlessly on demand. @@ -681,7 +647,7 @@ public final class Unpooled { } private static ByteBuf copiedBuffer(CharBuffer buffer, Charset charset) { - ByteBuffer dst = BufUtil.encodeString(buffer, charset); + ByteBuffer dst = ByteBufUtil.encodeString(buffer, charset); ByteBuf result = wrappedBuffer(dst.array()); result.writerIndex(dst.remaining()); return result; diff --git a/buffer/src/main/java/io/netty/buffer/UnpooledDirectByteBuf.java b/buffer/src/main/java/io/netty/buffer/UnpooledDirectByteBuf.java index b066299297..b9d49ac15a 100644 --- a/buffer/src/main/java/io/netty/buffer/UnpooledDirectByteBuf.java +++ b/buffer/src/main/java/io/netty/buffer/UnpooledDirectByteBuf.java @@ -26,8 +26,6 @@ import java.nio.ByteOrder; import java.nio.channels.ClosedChannelException; import java.nio.channels.GatheringByteChannel; import java.nio.channels.ScatteringByteChannel; -import java.util.ArrayDeque; -import java.util.Queue; /** * A NIO {@link ByteBuffer} based buffer. It is recommended to use {@link Unpooled#directBuffer(int)} @@ -43,7 +41,6 @@ public class UnpooledDirectByteBuf extends AbstractReferenceCountedByteBuf { private ByteBuffer tmpNioBuf; private int capacity; private boolean doNotFree; - private Queue suspendedDeallocations; /** * Creates a new direct buffer. @@ -111,11 +108,7 @@ public class UnpooledDirectByteBuf extends AbstractReferenceCountedByteBuf { if (doNotFree) { doNotFree = false; } else { - if (suspendedDeallocations == null) { - PlatformDependent.freeDirectBuffer(oldBuffer); - } else { - suspendedDeallocations.add(oldBuffer); - } + PlatformDependent.freeDirectBuffer(oldBuffer); } } @@ -527,37 +520,12 @@ public class UnpooledDirectByteBuf extends AbstractReferenceCountedByteBuf { this.buffer = null; - resumeIntermediaryDeallocations(); if (!doNotFree) { PlatformDependent.freeDirectBuffer(buffer); } leak.close(); } - @Override - public ByteBuf suspendIntermediaryDeallocations() { - ensureAccessible(); - if (suspendedDeallocations == null) { - suspendedDeallocations = new ArrayDeque(2); - } - return this; - } - - @Override - public ByteBuf resumeIntermediaryDeallocations() { - if (suspendedDeallocations == null) { - return this; - } - - Queue suspendedDeallocations = this.suspendedDeallocations; - this.suspendedDeallocations = null; - - for (ByteBuffer buf: suspendedDeallocations) { - PlatformDependent.freeDirectBuffer(buf); - } - return this; - } - @Override public ByteBuf unwrap() { return null; diff --git a/buffer/src/main/java/io/netty/buffer/UnpooledHeapByteBuf.java b/buffer/src/main/java/io/netty/buffer/UnpooledHeapByteBuf.java index affae8f8aa..ce70ff2f14 100644 --- a/buffer/src/main/java/io/netty/buffer/UnpooledHeapByteBuf.java +++ b/buffer/src/main/java/io/netty/buffer/UnpooledHeapByteBuf.java @@ -417,16 +417,6 @@ public class UnpooledHeapByteBuf extends AbstractReferenceCountedByteBuf { array = null; } - @Override - public ByteBuf suspendIntermediaryDeallocations() { - return this; - } - - @Override - public ByteBuf resumeIntermediaryDeallocations() { - return this; - } - @Override public ByteBuf unwrap() { return null; diff --git a/buffer/src/main/java/io/netty/buffer/UnpooledUnsafeDirectByteBuf.java b/buffer/src/main/java/io/netty/buffer/UnpooledUnsafeDirectByteBuf.java index 8875613271..3dbf665c09 100644 --- a/buffer/src/main/java/io/netty/buffer/UnpooledUnsafeDirectByteBuf.java +++ b/buffer/src/main/java/io/netty/buffer/UnpooledUnsafeDirectByteBuf.java @@ -26,8 +26,6 @@ import java.nio.ByteOrder; import java.nio.channels.ClosedChannelException; import java.nio.channels.GatheringByteChannel; import java.nio.channels.ScatteringByteChannel; -import java.util.ArrayDeque; -import java.util.Queue; /** * A NIO {@link ByteBuffer} based buffer. It is recommended to use {@link Unpooled#directBuffer(int)} @@ -46,7 +44,6 @@ public class UnpooledUnsafeDirectByteBuf extends AbstractReferenceCountedByteBuf private ByteBuffer tmpNioBuf; private int capacity; private boolean doNotFree; - private Queue suspendedDeallocations; /** * Creates a new direct buffer. @@ -114,11 +111,7 @@ public class UnpooledUnsafeDirectByteBuf extends AbstractReferenceCountedByteBuf if (doNotFree) { doNotFree = false; } else { - if (suspendedDeallocations == null) { - PlatformDependent.freeDirectBuffer(oldBuffer); - } else { - suspendedDeallocations.add(oldBuffer); - } + PlatformDependent.freeDirectBuffer(oldBuffer); } } @@ -459,37 +452,12 @@ public class UnpooledUnsafeDirectByteBuf extends AbstractReferenceCountedByteBuf this.buffer = null; - resumeIntermediaryDeallocations(); if (!doNotFree) { PlatformDependent.freeDirectBuffer(buffer); } leak.close(); } - @Override - public ByteBuf suspendIntermediaryDeallocations() { - ensureAccessible(); - if (suspendedDeallocations == null) { - suspendedDeallocations = new ArrayDeque(2); - } - return this; - } - - @Override - public ByteBuf resumeIntermediaryDeallocations() { - if (suspendedDeallocations == null) { - return this; - } - - Queue suspendedDeallocations = this.suspendedDeallocations; - this.suspendedDeallocations = null; - - for (ByteBuffer buf: suspendedDeallocations) { - PlatformDependent.freeDirectBuffer(buf); - } - return this; - } - @Override public ByteBuf unwrap() { return null; diff --git a/buffer/src/main/java/io/netty/buffer/UnreleasableByteBuf.java b/buffer/src/main/java/io/netty/buffer/UnreleasableByteBuf.java index fb8a226722..c56fc49b53 100644 --- a/buffer/src/main/java/io/netty/buffer/UnreleasableByteBuf.java +++ b/buffer/src/main/java/io/netty/buffer/UnreleasableByteBuf.java @@ -796,18 +796,6 @@ final class UnreleasableByteBuf implements ByteBuf { return buf.toString(index, length, charset); } - @Override - public ByteBuf suspendIntermediaryDeallocations() { - buf.suspendIntermediaryDeallocations(); - return this; - } - - @Override - public ByteBuf resumeIntermediaryDeallocations() { - buf.resumeIntermediaryDeallocations(); - return this; - } - @Override public int hashCode() { return buf.hashCode(); @@ -838,11 +826,6 @@ final class UnreleasableByteBuf implements ByteBuf { return this; } - @Override - public BufType type() { - return buf.type(); - } - @Override public boolean isReadable(int size) { return buf.isReadable(size); diff --git a/buffer/src/test/java/io/netty/buffer/AbstractCompositeByteBufTest.java b/buffer/src/test/java/io/netty/buffer/AbstractCompositeByteBufTest.java index 584f96a6b0..68fd19c4b3 100644 --- a/buffer/src/test/java/io/netty/buffer/AbstractCompositeByteBufTest.java +++ b/buffer/src/test/java/io/netty/buffer/AbstractCompositeByteBufTest.java @@ -142,20 +142,20 @@ public abstract class AbstractCompositeByteBufTest extends AbstractByteBufTest { a.writerIndex(a.writerIndex() + 1); b.writerIndex(b.writerIndex() + 1); assertEquals(a.writerIndex(), b.writerIndex()); - assertTrue(BufUtil.equals(a, b)); + assertTrue(ByteBufUtil.equals(a, b)); // now discard a.discardReadBytes(); b.discardReadBytes(); assertEquals(a.readerIndex(), b.readerIndex()); assertEquals(a.writerIndex(), b.writerIndex()); - assertTrue(BufUtil.equals(a, b)); + assertTrue(ByteBufUtil.equals(a, b)); a.resetReaderIndex(); b.resetReaderIndex(); assertEquals(a.readerIndex(), b.readerIndex()); a.resetWriterIndex(); b.resetWriterIndex(); assertEquals(a.writerIndex(), b.writerIndex()); - assertTrue(BufUtil.equals(a, b)); + assertTrue(ByteBufUtil.equals(a, b)); } @Test @@ -231,7 +231,7 @@ public abstract class AbstractCompositeByteBufTest extends AbstractByteBufTest { b = freeLater(wrappedBuffer( wrappedBuffer(new byte[] { 1 }).order(order), wrappedBuffer(new byte[] { 2 }).order(order))); - assertFalse(BufUtil.equals(a, b)); + assertFalse(ByteBufUtil.equals(a, b)); // Same content, same firstIndex, short length. a = freeLater(wrappedBuffer(new byte[] { 1, 2, 3 }).order(order)); @@ -239,28 +239,28 @@ public abstract class AbstractCompositeByteBufTest extends AbstractByteBufTest { wrappedBuffer(new byte[]{1}).order(order), wrappedBuffer(new byte[]{2}).order(order), wrappedBuffer(new byte[]{3}).order(order))); - assertTrue(BufUtil.equals(a, b)); + assertTrue(ByteBufUtil.equals(a, b)); // Same content, different firstIndex, short length. a = freeLater(wrappedBuffer(new byte[] { 1, 2, 3 }).order(order)); b = freeLater(wrappedBuffer( wrappedBuffer(new byte[] { 0, 1, 2, 3, 4 }, 1, 2).order(order), wrappedBuffer(new byte[] { 0, 1, 2, 3, 4 }, 3, 1).order(order))); - assertTrue(BufUtil.equals(a, b)); + assertTrue(ByteBufUtil.equals(a, b)); // Different content, same firstIndex, short length. a = freeLater(wrappedBuffer(new byte[] { 1, 2, 3 }).order(order)); b = freeLater(wrappedBuffer( wrappedBuffer(new byte[] { 1, 2 }).order(order), wrappedBuffer(new byte[] { 4 }).order(order))); - assertFalse(BufUtil.equals(a, b)); + assertFalse(ByteBufUtil.equals(a, b)); // Different content, different firstIndex, short length. a = freeLater(wrappedBuffer(new byte[] { 1, 2, 3 }).order(order)); b = freeLater(wrappedBuffer( wrappedBuffer(new byte[] { 0, 1, 2, 4, 5 }, 1, 2).order(order), wrappedBuffer(new byte[] { 0, 1, 2, 4, 5 }, 3, 1).order(order))); - assertFalse(BufUtil.equals(a, b)); + assertFalse(ByteBufUtil.equals(a, b)); // Same content, same firstIndex, long length. a = freeLater(wrappedBuffer(new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }).order(order)); @@ -268,28 +268,28 @@ public abstract class AbstractCompositeByteBufTest extends AbstractByteBufTest { wrappedBuffer(new byte[] { 1, 2, 3 }).order(order), wrappedBuffer(new byte[] { 4, 5, 6 }).order(order), wrappedBuffer(new byte[] { 7, 8, 9, 10 }).order(order))); - assertTrue(BufUtil.equals(a, b)); + assertTrue(ByteBufUtil.equals(a, b)); // Same content, different firstIndex, long length. a = freeLater(wrappedBuffer(new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }).order(order)); b = freeLater(wrappedBuffer( wrappedBuffer(new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}, 1, 5).order(order), wrappedBuffer(new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}, 6, 5).order(order))); - assertTrue(BufUtil.equals(a, b)); + assertTrue(ByteBufUtil.equals(a, b)); // Different content, same firstIndex, long length. a = freeLater(wrappedBuffer(new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }).order(order)); b = freeLater(wrappedBuffer( wrappedBuffer(new byte[] { 1, 2, 3, 4, 6 }).order(order), wrappedBuffer(new byte[] { 7, 8, 5, 9, 10 }).order(order))); - assertFalse(BufUtil.equals(a, b)); + assertFalse(ByteBufUtil.equals(a, b)); // Different content, different firstIndex, long length. a = freeLater(wrappedBuffer(new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }).order(order)); b = freeLater(wrappedBuffer( wrappedBuffer(new byte[] { 0, 1, 2, 3, 4, 6, 7, 8, 5, 9, 10, 11 }, 1, 5).order(order), wrappedBuffer(new byte[] { 0, 1, 2, 3, 4, 6, 7, 8, 5, 9, 10, 11 }, 6, 5).order(order))); - assertFalse(BufUtil.equals(a, b)); + assertFalse(ByteBufUtil.equals(a, b)); } @Test @@ -345,7 +345,7 @@ public abstract class AbstractCompositeByteBufTest extends AbstractByteBufTest { // to enable writeBytes b.writerIndex(b.writerIndex() - 1); b.writeBytes(wrappedBuffer(new byte[] { 2 }).order(order)); - assertFalse(BufUtil.equals(a, b)); + assertFalse(ByteBufUtil.equals(a, b)); // Same content, same firstIndex, short length. a = wrappedBuffer(new byte[] { 1, 2, 3 }).order(order); @@ -354,7 +354,7 @@ public abstract class AbstractCompositeByteBufTest extends AbstractByteBufTest { b.writerIndex(b.writerIndex() - 2); b.writeBytes(wrappedBuffer(new byte[] { 2 }).order(order)); b.writeBytes(wrappedBuffer(new byte[] { 3 }).order(order)); - assertTrue(BufUtil.equals(a, b)); + assertTrue(ByteBufUtil.equals(a, b)); // Same content, different firstIndex, short length. a = wrappedBuffer(new byte[] { 1, 2, 3 }).order(order); @@ -362,7 +362,7 @@ public abstract class AbstractCompositeByteBufTest extends AbstractByteBufTest { // to enable writeBytes b.writerIndex(b.writerIndex() - 1); b.writeBytes(wrappedBuffer(new byte[] { 0, 1, 2, 3, 4 }, 3, 1).order(order)); - assertTrue(BufUtil.equals(a, b)); + assertTrue(ByteBufUtil.equals(a, b)); // Different content, same firstIndex, short length. a = wrappedBuffer(new byte[] { 1, 2, 3 }).order(order); @@ -370,7 +370,7 @@ public abstract class AbstractCompositeByteBufTest extends AbstractByteBufTest { // to enable writeBytes b.writerIndex(b.writerIndex() - 1); b.writeBytes(wrappedBuffer(new byte[] { 4 }).order(order)); - assertFalse(BufUtil.equals(a, b)); + assertFalse(ByteBufUtil.equals(a, b)); // Different content, different firstIndex, short length. a = wrappedBuffer(new byte[] { 1, 2, 3 }).order(order); @@ -378,7 +378,7 @@ public abstract class AbstractCompositeByteBufTest extends AbstractByteBufTest { // to enable writeBytes b.writerIndex(b.writerIndex() - 1); b.writeBytes(wrappedBuffer(new byte[] { 0, 1, 2, 4, 5 }, 3, 1).order(order)); - assertFalse(BufUtil.equals(a, b)); + assertFalse(ByteBufUtil.equals(a, b)); // Same content, same firstIndex, long length. a = wrappedBuffer(new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }).order(order); @@ -387,7 +387,7 @@ public abstract class AbstractCompositeByteBufTest extends AbstractByteBufTest { b.writerIndex(b.writerIndex() - 7); b.writeBytes(wrappedBuffer(new byte[] { 4, 5, 6 }).order(order)); b.writeBytes(wrappedBuffer(new byte[] { 7, 8, 9, 10 }).order(order)); - assertTrue(BufUtil.equals(a, b)); + assertTrue(ByteBufUtil.equals(a, b)); // Same content, different firstIndex, long length. a = wrappedBuffer(new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }).order(order); @@ -395,7 +395,7 @@ public abstract class AbstractCompositeByteBufTest extends AbstractByteBufTest { // to enable writeBytes b.writerIndex(b.writerIndex() - 5); b.writeBytes(wrappedBuffer(new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}, 6, 5).order(order)); - assertTrue(BufUtil.equals(a, b)); + assertTrue(ByteBufUtil.equals(a, b)); // Different content, same firstIndex, long length. a = wrappedBuffer(new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }).order(order); @@ -403,7 +403,7 @@ public abstract class AbstractCompositeByteBufTest extends AbstractByteBufTest { // to enable writeBytes b.writerIndex(b.writerIndex() - 5); b.writeBytes(wrappedBuffer(new byte[] { 7, 8, 5, 9, 10 }).order(order)); - assertFalse(BufUtil.equals(a, b)); + assertFalse(ByteBufUtil.equals(a, b)); // Different content, different firstIndex, long length. a = wrappedBuffer(new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }).order(order); @@ -411,7 +411,7 @@ public abstract class AbstractCompositeByteBufTest extends AbstractByteBufTest { // to enable writeBytes b.writerIndex(b.writerIndex() - 5); b.writeBytes(wrappedBuffer(new byte[] { 0, 1, 2, 3, 4, 6, 7, 8, 5, 9, 10, 11 }, 6, 5).order(order)); - assertFalse(BufUtil.equals(a, b)); + assertFalse(ByteBufUtil.equals(a, b)); } @Test diff --git a/buffer/src/test/java/io/netty/buffer/UnpooledTest.java b/buffer/src/test/java/io/netty/buffer/UnpooledTest.java index 07859fa680..6d164e5bdc 100644 --- a/buffer/src/test/java/io/netty/buffer/UnpooledTest.java +++ b/buffer/src/test/java/io/netty/buffer/UnpooledTest.java @@ -97,7 +97,7 @@ public class UnpooledTest { for (Entry e: map.entrySet()) { assertEquals( e.getValue().intValue(), - BufUtil.hashCode(wrappedBuffer(e.getKey()))); + ByteBufUtil.hashCode(wrappedBuffer(e.getKey()))); } } @@ -108,47 +108,47 @@ public class UnpooledTest { // Different length. a = wrappedBuffer(new byte[] { 1 }); b = wrappedBuffer(new byte[] { 1, 2 }); - assertFalse(BufUtil.equals(a, b)); + assertFalse(ByteBufUtil.equals(a, b)); // Same content, same firstIndex, short length. a = wrappedBuffer(new byte[] { 1, 2, 3 }); b = wrappedBuffer(new byte[] { 1, 2, 3 }); - assertTrue(BufUtil.equals(a, b)); + assertTrue(ByteBufUtil.equals(a, b)); // Same content, different firstIndex, short length. a = wrappedBuffer(new byte[] { 1, 2, 3 }); b = wrappedBuffer(new byte[] { 0, 1, 2, 3, 4 }, 1, 3); - assertTrue(BufUtil.equals(a, b)); + assertTrue(ByteBufUtil.equals(a, b)); // Different content, same firstIndex, short length. a = wrappedBuffer(new byte[] { 1, 2, 3 }); b = wrappedBuffer(new byte[] { 1, 2, 4 }); - assertFalse(BufUtil.equals(a, b)); + assertFalse(ByteBufUtil.equals(a, b)); // Different content, different firstIndex, short length. a = wrappedBuffer(new byte[] { 1, 2, 3 }); b = wrappedBuffer(new byte[] { 0, 1, 2, 4, 5 }, 1, 3); - assertFalse(BufUtil.equals(a, b)); + assertFalse(ByteBufUtil.equals(a, b)); // Same content, same firstIndex, long length. a = wrappedBuffer(new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }); b = wrappedBuffer(new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }); - assertTrue(BufUtil.equals(a, b)); + assertTrue(ByteBufUtil.equals(a, b)); // Same content, different firstIndex, long length. a = wrappedBuffer(new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }); b = wrappedBuffer(new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}, 1, 10); - assertTrue(BufUtil.equals(a, b)); + assertTrue(ByteBufUtil.equals(a, b)); // Different content, same firstIndex, long length. a = wrappedBuffer(new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }); b = wrappedBuffer(new byte[] { 1, 2, 3, 4, 6, 7, 8, 5, 9, 10 }); - assertFalse(BufUtil.equals(a, b)); + assertFalse(ByteBufUtil.equals(a, b)); // Different content, different firstIndex, long length. a = wrappedBuffer(new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }); b = wrappedBuffer(new byte[] { 0, 1, 2, 3, 4, 6, 7, 8, 5, 9, 10, 11 }, 1, 10); - assertFalse(BufUtil.equals(a, b)); + assertFalse(ByteBufUtil.equals(a, b)); } @Test @@ -174,11 +174,11 @@ public class UnpooledTest { for (int i = 0; i < expected.size(); i ++) { for (int j = 0; j < expected.size(); j ++) { if (i == j) { - assertEquals(0, BufUtil.compare(expected.get(i), expected.get(j))); + assertEquals(0, ByteBufUtil.compare(expected.get(i), expected.get(j))); } else if (i < j) { - assertTrue(BufUtil.compare(expected.get(i), expected.get(j)) < 0); + assertTrue(ByteBufUtil.compare(expected.get(i), expected.get(j)) < 0); } else { - assertTrue(BufUtil.compare(expected.get(i), expected.get(j)) > 0); + assertTrue(ByteBufUtil.compare(expected.get(i), expected.get(j)) > 0); } } } @@ -217,12 +217,12 @@ public class UnpooledTest { @Test public void testCompare2() { - assertTrue(BufUtil.compare( + assertTrue(ByteBufUtil.compare( wrappedBuffer(new byte[]{(byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF}), wrappedBuffer(new byte[]{(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00})) > 0); - assertTrue(BufUtil.compare( + assertTrue(ByteBufUtil.compare( wrappedBuffer(new byte[]{(byte) 0xFF}), wrappedBuffer(new byte[]{(byte) 0x00})) > 0); @@ -327,14 +327,14 @@ public class UnpooledTest { @Test public void testHexDump() { - assertEquals("", BufUtil.hexDump(EMPTY_BUFFER)); + assertEquals("", ByteBufUtil.hexDump(EMPTY_BUFFER)); - assertEquals("123456", BufUtil.hexDump(wrappedBuffer( + assertEquals("123456", ByteBufUtil.hexDump(wrappedBuffer( new byte[]{ 0x12, 0x34, 0x56 }))); - assertEquals("1234567890abcdef", BufUtil.hexDump(wrappedBuffer( + assertEquals("1234567890abcdef", ByteBufUtil.hexDump(wrappedBuffer( new byte[]{ 0x12, 0x34, 0x56, 0x78, (byte) 0x90, (byte) 0xAB, (byte) 0xCD, (byte) 0xEF @@ -343,8 +343,8 @@ public class UnpooledTest { @Test public void testSwapMedium() { - assertEquals(0x563412, BufUtil.swapMedium(0x123456)); - assertEquals(0x80, BufUtil.swapMedium(0x800000)); + assertEquals(0x563412, ByteBufUtil.swapMedium(0x123456)); + assertEquals(0x80, ByteBufUtil.swapMedium(0x800000)); } @Test diff --git a/codec-http/pom.xml b/codec-http/pom.xml index 979864cb7a..4e187b74c1 100644 --- a/codec-http/pom.xml +++ b/codec-http/pom.xml @@ -20,7 +20,7 @@ io.netty netty-parent - 4.0.0.Final-SNAPSHOT + 4.0.0.CR4-SNAPSHOT netty-codec-http diff --git a/codec-http/src/main/java/io/netty/handler/codec/http/HttpClientCodec.java b/codec-http/src/main/java/io/netty/handler/codec/http/HttpClientCodec.java index a91c54efa9..3c82ebd12b 100644 --- a/codec-http/src/main/java/io/netty/handler/codec/http/HttpClientCodec.java +++ b/codec-http/src/main/java/io/netty/handler/codec/http/HttpClientCodec.java @@ -16,13 +16,10 @@ package io.netty.handler.codec.http; import io.netty.buffer.ByteBuf; -import io.netty.buffer.FilteredMessageBuf; -import io.netty.buffer.MessageBuf; import io.netty.channel.Channel; import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.ChannelInboundByteHandler; -import io.netty.channel.ChannelOutboundMessageHandler; import io.netty.channel.CombinedChannelDuplexHandler; +import io.netty.channel.MessageList; import io.netty.handler.codec.PrematureChannelClosureException; import java.util.ArrayDeque; @@ -44,8 +41,7 @@ import java.util.concurrent.atomic.AtomicLong; * @see HttpServerCodec */ public final class HttpClientCodec - extends CombinedChannelDuplexHandler - implements ChannelInboundByteHandler, ChannelOutboundMessageHandler { + extends CombinedChannelDuplexHandler { /** A queue that is used for correlating a request and a response. */ private final Queue queue = new ArrayDeque(); @@ -66,11 +62,11 @@ public final class HttpClientCodec } public void setSingleDecode(boolean singleDecode) { - decoder().setSingleDecode(singleDecode); + inboundHandler().setSingleDecode(singleDecode); } public boolean isSingleDecode() { - return decoder().isSingleDecode(); + return inboundHandler().isSingleDecode(); } /** @@ -86,29 +82,6 @@ public final class HttpClientCodec this.failOnMissingResponse = failOnMissingResponse; } - private Decoder decoder() { - return (Decoder) stateHandler(); - } - - private Encoder encoder() { - return (Encoder) operationHandler(); - } - - @Override - public ByteBuf newInboundBuffer(ChannelHandlerContext ctx) throws Exception { - return decoder().newInboundBuffer(ctx); - } - - @Override - public void discardInboundReadBytes(ChannelHandlerContext ctx) throws Exception { - decoder().discardInboundReadBytes(ctx); - } - - @Override - public MessageBuf newOutboundBuffer(ChannelHandlerContext ctx) throws Exception { - return encoder().newOutboundBuffer(ctx); - } - private final class Encoder extends HttpRequestEncoder { @Override @@ -137,7 +110,7 @@ public final class HttpClientCodec @Override protected void decode( - ChannelHandlerContext ctx, ByteBuf buffer, MessageBuf out) throws Exception { + ChannelHandlerContext ctx, ByteBuf buffer, MessageList out) throws Exception { if (done) { int readable = actualReadableBytes(); if (readable == 0) { @@ -147,16 +120,14 @@ public final class HttpClientCodec } out.add(buffer.readBytes(readable)); } else { - if (failOnMissingResponse) { - out = new FilteredMessageBuf(out) { - @Override - protected Object filter(Object msg) { - decrement(msg); - return msg; - } - }; - } + int oldSize = out.size(); super.decode(ctx, buffer, out); + if (failOnMissingResponse) { + int size = out.size(); + for (int i = oldSize; i < size; i++) { + decrement(out.get(i)); + } + } } } diff --git a/codec-http/src/main/java/io/netty/handler/codec/http/HttpContentCompressor.java b/codec-http/src/main/java/io/netty/handler/codec/http/HttpContentCompressor.java index f319f8f581..5fcef790d0 100644 --- a/codec-http/src/main/java/io/netty/handler/codec/http/HttpContentCompressor.java +++ b/codec-http/src/main/java/io/netty/handler/codec/http/HttpContentCompressor.java @@ -15,7 +15,7 @@ */ package io.netty.handler.codec.http; -import io.netty.channel.embedded.EmbeddedByteChannel; +import io.netty.channel.embedded.EmbeddedChannel; import io.netty.handler.codec.compression.ZlibCodecFactory; import io.netty.handler.codec.compression.ZlibWrapper; import io.netty.util.internal.StringUtil; @@ -119,7 +119,7 @@ public class HttpContentCompressor extends HttpContentEncoder { return new Result( targetContentEncoding, - new EmbeddedByteChannel(ZlibCodecFactory.newZlibEncoder( + new EmbeddedChannel(ZlibCodecFactory.newZlibEncoder( wrapper, compressionLevel, windowBits, memLevel))); } diff --git a/codec-http/src/main/java/io/netty/handler/codec/http/HttpContentDecoder.java b/codec-http/src/main/java/io/netty/handler/codec/http/HttpContentDecoder.java index 2d00bf9647..5e5ac73687 100644 --- a/codec-http/src/main/java/io/netty/handler/codec/http/HttpContentDecoder.java +++ b/codec-http/src/main/java/io/netty/handler/codec/http/HttpContentDecoder.java @@ -15,21 +15,19 @@ */ package io.netty.handler.codec.http; -import io.netty.buffer.BufUtil; import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBufHolder; -import io.netty.buffer.MessageBuf; +import io.netty.buffer.ByteBufUtil; import io.netty.buffer.Unpooled; import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.embedded.EmbeddedByteChannel; +import io.netty.channel.MessageList; +import io.netty.channel.embedded.EmbeddedChannel; import io.netty.handler.codec.MessageToMessageDecoder; -import java.util.Collections; - /** * Decodes the content of the received {@link HttpRequest} and {@link HttpContent}. * The original content is replaced with the new content decoded by the - * {@link EmbeddedByteChannel}, which is created by {@link #newContentDecoder(String)}. + * {@link EmbeddedChannel}, which is created by {@link #newContentDecoder(String)}. * Once decoding is finished, the value of the 'Content-Encoding' * header is set to the target content encoding, as returned by {@link #getTargetContentEncoding(String)}. * Also, the 'Content-Length' header is updated to the length of the @@ -47,20 +45,20 @@ import java.util.Collections; */ public abstract class HttpContentDecoder extends MessageToMessageDecoder { - private EmbeddedByteChannel decoder; + private EmbeddedChannel decoder; private HttpMessage message; private boolean decodeStarted; private boolean continueResponse; @Override - protected void decode(ChannelHandlerContext ctx, HttpObject msg, MessageBuf out) throws Exception { + protected void decode(ChannelHandlerContext ctx, HttpObject msg, MessageList out) throws Exception { if (msg instanceof HttpResponse && ((HttpResponse) msg).getStatus().code() == 100) { if (!(msg instanceof LastHttpContent)) { continueResponse = true; } // 100-continue response must be passed through. - out.add(BufUtil.retain(msg)); + out.add(ByteBufUtil.retain(msg)); return; } @@ -69,7 +67,7 @@ public abstract class HttpContentDecoder extends MessageToMessageDecodercontentEncoding. * * @param contentEncoding the value of the {@code "Content-Encoding"} header - * @return a new {@link EmbeddedByteChannel} if the specified encoding is supported. + * @return a new {@link EmbeddedChannel} if the specified encoding is supported. * {@code null} otherwise (alternatively, you can throw an exception * to block unknown encoding). */ - protected abstract EmbeddedByteChannel newContentDecoder(String contentEncoding) throws Exception; + protected abstract EmbeddedChannel newContentDecoder(String contentEncoding) throws Exception; /** * Returns the expected content encoding of the decoded content. diff --git a/codec-http/src/main/java/io/netty/handler/codec/http/HttpContentDecompressor.java b/codec-http/src/main/java/io/netty/handler/codec/http/HttpContentDecompressor.java index 254a483dae..e328477640 100644 --- a/codec-http/src/main/java/io/netty/handler/codec/http/HttpContentDecompressor.java +++ b/codec-http/src/main/java/io/netty/handler/codec/http/HttpContentDecompressor.java @@ -15,7 +15,7 @@ */ package io.netty.handler.codec.http; -import io.netty.channel.embedded.EmbeddedByteChannel; +import io.netty.channel.embedded.EmbeddedChannel; import io.netty.handler.codec.compression.ZlibCodecFactory; import io.netty.handler.codec.compression.ZlibWrapper; @@ -26,13 +26,13 @@ import io.netty.handler.codec.compression.ZlibWrapper; */ public class HttpContentDecompressor extends HttpContentDecoder { @Override - protected EmbeddedByteChannel newContentDecoder(String contentEncoding) throws Exception { + protected EmbeddedChannel newContentDecoder(String contentEncoding) throws Exception { if ("gzip".equalsIgnoreCase(contentEncoding) || "x-gzip".equalsIgnoreCase(contentEncoding)) { - return new EmbeddedByteChannel(ZlibCodecFactory.newZlibDecoder(ZlibWrapper.GZIP)); + return new EmbeddedChannel(ZlibCodecFactory.newZlibDecoder(ZlibWrapper.GZIP)); } if ("deflate".equalsIgnoreCase(contentEncoding) || "x-deflate".equalsIgnoreCase(contentEncoding)) { // To be strict, 'deflate' means ZLIB, but some servers were not implemented correctly. - return new EmbeddedByteChannel(ZlibCodecFactory.newZlibDecoder(ZlibWrapper.ZLIB_OR_NONE)); + return new EmbeddedChannel(ZlibCodecFactory.newZlibDecoder(ZlibWrapper.ZLIB_OR_NONE)); } // 'identity' or unsupported diff --git a/codec-http/src/main/java/io/netty/handler/codec/http/HttpContentEncoder.java b/codec-http/src/main/java/io/netty/handler/codec/http/HttpContentEncoder.java index d6be9c34c8..fb5b46c19a 100644 --- a/codec-http/src/main/java/io/netty/handler/codec/http/HttpContentEncoder.java +++ b/codec-http/src/main/java/io/netty/handler/codec/http/HttpContentEncoder.java @@ -15,25 +15,24 @@ */ package io.netty.handler.codec.http; -import io.netty.buffer.BufUtil; import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBufHolder; -import io.netty.buffer.MessageBuf; +import io.netty.buffer.ByteBufUtil; import io.netty.buffer.Unpooled; import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.embedded.EmbeddedByteChannel; +import io.netty.channel.MessageList; +import io.netty.channel.embedded.EmbeddedChannel; import io.netty.handler.codec.MessageToMessageCodec; import io.netty.handler.codec.http.HttpHeaders.Names; import io.netty.handler.codec.http.HttpHeaders.Values; import java.util.ArrayDeque; -import java.util.Collections; import java.util.Queue; /** * Encodes the content of the outbound {@link HttpResponse} and {@link HttpContent}. * The original content is replaced with the new content encoded by the - * {@link EmbeddedByteChannel}, which is created by {@link #beginEncode(HttpResponse, String)}. + * {@link EmbeddedChannel}, which is created by {@link #beginEncode(HttpResponse, String)}. * Once encoding is finished, the value of the 'Content-Encoding' header * is set to the target content encoding, as returned by * {@link #beginEncode(HttpResponse, String)}. @@ -62,7 +61,7 @@ public abstract class HttpContentEncoder extends MessageToMessageCodec acceptEncodingQueue = new ArrayDeque(); private String acceptEncoding; - private EmbeddedByteChannel encoder; + private EmbeddedChannel encoder; private State state = State.AWAIT_HEADERS; @Override @@ -71,18 +70,18 @@ public abstract class HttpContentEncoder extends MessageToMessageCodec out) + protected void decode(ChannelHandlerContext ctx, HttpRequest msg, MessageList out) throws Exception { String acceptedEncoding = msg.headers().get(HttpHeaders.Names.ACCEPT_ENCODING); if (acceptedEncoding == null) { acceptedEncoding = HttpHeaders.Values.IDENTITY; } acceptEncodingQueue.add(acceptedEncoding); - out.add(BufUtil.retain(msg)); + out.add(ByteBufUtil.retain(msg)); } @Override - protected void encode(ChannelHandlerContext ctx, HttpObject msg, MessageBuf out) throws Exception { + protected void encode(ChannelHandlerContext ctx, HttpObject msg, MessageList out) throws Exception { final boolean isFull = msg instanceof HttpResponse && msg instanceof LastHttpContent; switch (state) { case AWAIT_HEADERS: { @@ -93,7 +92,7 @@ public abstract class HttpContentEncoder extends MessageToMessageCodec { } @Override - protected void decode(ChannelHandlerContext ctx, HttpObject msg, MessageBuf out) throws Exception { + protected void decode(ChannelHandlerContext ctx, HttpObject msg, MessageList out) throws Exception { FullHttpMessage currentMessage = this.currentMessage; if (msg instanceof HttpMessage) { @@ -129,7 +129,7 @@ public class HttpObjectAggregator extends MessageToMessageDecoder { if (!m.getDecoderResult().isSuccess()) { removeTransferEncodingChunked(m); this.currentMessage = null; - out.add(BufUtil.retain(m)); + out.add(ByteBufUtil.retain(m)); return; } if (msg instanceof HttpRequest) { diff --git a/codec-http/src/main/java/io/netty/handler/codec/http/HttpObjectDecoder.java b/codec-http/src/main/java/io/netty/handler/codec/http/HttpObjectDecoder.java index c30eabe9ef..f1100fe0e0 100644 --- a/codec-http/src/main/java/io/netty/handler/codec/http/HttpObjectDecoder.java +++ b/codec-http/src/main/java/io/netty/handler/codec/http/HttpObjectDecoder.java @@ -16,10 +16,10 @@ package io.netty.handler.codec.http; import io.netty.buffer.ByteBuf; -import io.netty.buffer.MessageBuf; import io.netty.buffer.Unpooled; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelPipeline; +import io.netty.channel.MessageList; import io.netty.handler.codec.DecoderResult; import io.netty.handler.codec.ReplayingDecoder; import io.netty.handler.codec.TooLongFrameException; @@ -168,7 +168,7 @@ public abstract class HttpObjectDecoder extends ReplayingDecoder out) throws Exception { + protected void decode(ChannelHandlerContext ctx, ByteBuf buffer, MessageList out) throws Exception { switch (state()) { case SKIP_CONTROL_CHARS: { try { @@ -449,7 +449,7 @@ public abstract class HttpObjectDecoder extends ReplayingDecoder out) { + private void reset(MessageList out) { if (out != null) { HttpMessage message = this.message; ByteBuf content = this.content; @@ -500,7 +500,7 @@ public abstract class HttpObjectDecoder extends ReplayingDecoder out) { + private void readFixedLengthContent(ByteBuf buffer, MessageList out) { //we have a content-length so we just read the correct number of bytes long length = HttpHeaders.getContentLength(message, -1); assert length <= Integer.MAX_VALUE; diff --git a/codec-http/src/main/java/io/netty/handler/codec/http/HttpObjectEncoder.java b/codec-http/src/main/java/io/netty/handler/codec/http/HttpObjectEncoder.java index bdb7cbbf40..edcaf7c036 100644 --- a/codec-http/src/main/java/io/netty/handler/codec/http/HttpObjectEncoder.java +++ b/codec-http/src/main/java/io/netty/handler/codec/http/HttpObjectEncoder.java @@ -40,7 +40,7 @@ import static io.netty.handler.codec.http.HttpConstants.*; */ public abstract class HttpObjectEncoder extends MessageToByteEncoder { private static final byte[] CRLF = { CR, LF }; - private static final byte[] CRLF_END = { CR, LF, 0 }; + private static final byte[] ZERO_CRLF = { '0', CR, LF }; private static final byte[] HEADER_SEPARATOR = { COLON , SP }; private static final int ST_INIT = 0; private static final int ST_CONTENT_NON_CHUNK = 1; @@ -93,7 +93,7 @@ public abstract class HttpObjectEncoder extends MessageTo } if (chunk instanceof LastHttpContent) { - out.writeBytes(CRLF_END); + out.writeBytes(ZERO_CRLF); encodeTrailingHeaders(out, (LastHttpContent) chunk); out.writeBytes(CRLF); diff --git a/codec-http/src/main/java/io/netty/handler/codec/http/HttpServerCodec.java b/codec-http/src/main/java/io/netty/handler/codec/http/HttpServerCodec.java index 2018362ba4..eabe8a1e8b 100644 --- a/codec-http/src/main/java/io/netty/handler/codec/http/HttpServerCodec.java +++ b/codec-http/src/main/java/io/netty/handler/codec/http/HttpServerCodec.java @@ -15,11 +15,6 @@ */ package io.netty.handler.codec.http; -import io.netty.buffer.ByteBuf; -import io.netty.buffer.MessageBuf; -import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.ChannelInboundByteHandler; -import io.netty.channel.ChannelOutboundMessageHandler; import io.netty.channel.CombinedChannelDuplexHandler; @@ -30,8 +25,7 @@ import io.netty.channel.CombinedChannelDuplexHandler; * @see HttpClientCodec */ public final class HttpServerCodec - extends CombinedChannelDuplexHandler - implements ChannelInboundByteHandler, ChannelOutboundMessageHandler { + extends CombinedChannelDuplexHandler { /** * Creates a new instance with the default decoder options @@ -48,27 +42,4 @@ public final class HttpServerCodec public HttpServerCodec(int maxInitialLineLength, int maxHeaderSize, int maxChunkSize) { super(new HttpRequestDecoder(maxInitialLineLength, maxHeaderSize, maxChunkSize), new HttpResponseEncoder()); } - - private HttpRequestDecoder decoder() { - return (HttpRequestDecoder) stateHandler(); - } - - private HttpResponseEncoder encoder() { - return (HttpResponseEncoder) operationHandler(); - } - - @Override - public ByteBuf newInboundBuffer(ChannelHandlerContext ctx) throws Exception { - return decoder().newInboundBuffer(ctx); - } - - @Override - public void discardInboundReadBytes(ChannelHandlerContext ctx) throws Exception { - decoder().discardInboundReadBytes(ctx); - } - - @Override - public MessageBuf newOutboundBuffer(ChannelHandlerContext ctx) throws Exception { - return encoder().newOutboundBuffer(ctx); - } } diff --git a/codec-http/src/main/java/io/netty/handler/codec/http/multipart/HttpPostRequestDecoder.java b/codec-http/src/main/java/io/netty/handler/codec/http/multipart/HttpPostRequestDecoder.java index 5057ae92e5..fb65bdfffc 100644 --- a/codec-http/src/main/java/io/netty/handler/codec/http/multipart/HttpPostRequestDecoder.java +++ b/codec-http/src/main/java/io/netty/handler/codec/http/multipart/HttpPostRequestDecoder.java @@ -15,7 +15,6 @@ */ package io.netty.handler.codec.http.multipart; -import io.netty.buffer.BufUtil; import io.netty.buffer.ByteBuf; import io.netty.handler.codec.DecoderException; import io.netty.handler.codec.http.HttpConstants; diff --git a/codec-http/src/main/java/io/netty/handler/codec/http/multipart/HttpPostRequestEncoder.java b/codec-http/src/main/java/io/netty/handler/codec/http/multipart/HttpPostRequestEncoder.java index 41ede3403e..adf46f5f24 100644 --- a/codec-http/src/main/java/io/netty/handler/codec/http/multipart/HttpPostRequestEncoder.java +++ b/codec-http/src/main/java/io/netty/handler/codec/http/multipart/HttpPostRequestEncoder.java @@ -16,7 +16,7 @@ package io.netty.handler.codec.http.multipart; import io.netty.buffer.ByteBuf; -import io.netty.buffer.MessageBuf; +import io.netty.channel.MessageList; import io.netty.handler.codec.DecoderResult; import io.netty.handler.codec.http.DefaultFullHttpRequest; import io.netty.handler.codec.http.DefaultHttpContent; @@ -943,7 +943,7 @@ public class HttpPostRequestEncoder implements ChunkedMessageInput * if the encoding is in error */ @Override - public boolean readChunk(MessageBuf buffer) throws ErrorDataEncoderException { + public boolean readChunk(MessageList buffer) throws ErrorDataEncoderException { if (isLastChunkSent) { return false; } else { diff --git a/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocket00FrameDecoder.java b/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocket00FrameDecoder.java index d1d486f2d2..c5bd9b02d2 100644 --- a/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocket00FrameDecoder.java +++ b/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocket00FrameDecoder.java @@ -16,8 +16,8 @@ package io.netty.handler.codec.http.websocketx; import io.netty.buffer.ByteBuf; -import io.netty.buffer.MessageBuf; import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.MessageList; import io.netty.handler.codec.ReplayingDecoder; import io.netty.handler.codec.TooLongFrameException; @@ -50,7 +50,7 @@ public class WebSocket00FrameDecoder extends ReplayingDecoder { } @Override - protected void decode(ChannelHandlerContext ctx, ByteBuf in, MessageBuf out) throws Exception { + protected void decode(ChannelHandlerContext ctx, ByteBuf in, MessageList out) throws Exception { // Discard all data received if closing handshake was received before. if (receivedClosingHandshake) { in.skipBytes(actualReadableBytes()); diff --git a/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocket08FrameDecoder.java b/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocket08FrameDecoder.java index 2e0be188d7..8032d5ec48 100644 --- a/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocket08FrameDecoder.java +++ b/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocket08FrameDecoder.java @@ -54,9 +54,10 @@ package io.netty.handler.codec.http.websocketx; import io.netty.buffer.ByteBuf; -import io.netty.buffer.MessageBuf; +import io.netty.buffer.Unpooled; import io.netty.channel.ChannelFutureListener; import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.MessageList; import io.netty.handler.codec.CorruptedFrameException; import io.netty.handler.codec.ReplayingDecoder; import io.netty.handler.codec.TooLongFrameException; @@ -89,6 +90,7 @@ public class WebSocket08FrameDecoder extends ReplayingDecoder out) throws Exception { + protected void decode(ChannelHandlerContext ctx, ByteBuf in, MessageList out) throws Exception { // Discard all data received if closing handshake was received before. if (receivedClosingHandshake) { @@ -126,248 +128,267 @@ public class WebSocket08FrameDecoder extends ReplayingDecoder> 4; - frameOpcode = b & 0x0F; + // FIN, RSV, OPCODE + byte b = in.readByte(); + frameFinalFlag = (b & 0x80) != 0; + frameRsv = (b & 0x70) >> 4; + frameOpcode = b & 0x0F; - if (logger.isDebugEnabled()) { - logger.debug("Decoding WebSocket Frame opCode={}", frameOpcode); - } + if (logger.isDebugEnabled()) { + logger.debug("Decoding WebSocket Frame opCode={}", frameOpcode); + } - // MASK, PAYLOAD LEN 1 - b = in.readByte(); - boolean frameMasked = (b & 0x80) != 0; - int framePayloadLen1 = b & 0x7F; + // MASK, PAYLOAD LEN 1 + b = in.readByte(); + boolean frameMasked = (b & 0x80) != 0; + int framePayloadLen1 = b & 0x7F; - if (frameRsv != 0 && !allowExtensions) { - protocolViolation(ctx, "RSV != 0 and no extension negotiated, RSV:" + frameRsv); - return; - } - - if (maskedPayload && !frameMasked) { - protocolViolation(ctx, "unmasked client to server frame"); - return; - } - if (frameOpcode > 7) { // control frame (have MSB in opcode set) - - // control frames MUST NOT be fragmented - if (!frameFinalFlag) { - protocolViolation(ctx, "fragmented control frame"); + if (frameRsv != 0 && !allowExtensions) { + protocolViolation(ctx, "RSV != 0 and no extension negotiated, RSV:" + frameRsv); return; } - // control frames MUST have payload 125 octets or less - if (framePayloadLen1 > 125) { - protocolViolation(ctx, "control frame with payload length > 125 octets"); + if (maskedPayload && !frameMasked) { + protocolViolation(ctx, "unmasked client to server frame"); return; } + if (frameOpcode > 7) { // control frame (have MSB in opcode set) - // check for reserved control frame opcodes - if (!(frameOpcode == OPCODE_CLOSE || frameOpcode == OPCODE_PING || frameOpcode == OPCODE_PONG)) { - protocolViolation(ctx, "control frame using reserved opcode " + frameOpcode); - return; - } + // control frames MUST NOT be fragmented + if (!frameFinalFlag) { + protocolViolation(ctx, "fragmented control frame"); + return; + } - // close frame : if there is a body, the first two bytes of the - // body MUST be a 2-byte unsigned integer (in network byte - // order) representing a getStatus code - if (frameOpcode == 8 && framePayloadLen1 == 1) { - protocolViolation(ctx, "received close control frame with payload len 1"); - return; - } - } else { // data frame - // check for reserved data frame opcodes - if (!(frameOpcode == OPCODE_CONT || frameOpcode == OPCODE_TEXT || frameOpcode == OPCODE_BINARY)) { - protocolViolation(ctx, "data frame using reserved opcode " + frameOpcode); - return; - } + // control frames MUST have payload 125 octets or less + if (framePayloadLen1 > 125) { + protocolViolation(ctx, "control frame with payload length > 125 octets"); + return; + } - // check opcode vs message fragmentation state 1/2 - if (fragmentedFramesCount == 0 && frameOpcode == OPCODE_CONT) { - protocolViolation(ctx, "received continuation data frame outside fragmented message"); - return; - } + // check for reserved control frame opcodes + if (!(frameOpcode == OPCODE_CLOSE || frameOpcode == OPCODE_PING + || frameOpcode == OPCODE_PONG)) { + protocolViolation(ctx, "control frame using reserved opcode " + frameOpcode); + return; + } - // check opcode vs message fragmentation state 2/2 - if (fragmentedFramesCount != 0 && frameOpcode != OPCODE_CONT && frameOpcode != OPCODE_PING) { - protocolViolation(ctx, "received non-continuation data frame while inside fragmented message"); - return; - } - } + // close frame : if there is a body, the first two bytes of the + // body MUST be a 2-byte unsigned integer (in network byte + // order) representing a getStatus code + if (frameOpcode == 8 && framePayloadLen1 == 1) { + protocolViolation(ctx, "received close control frame with payload len 1"); + return; + } + } else { // data frame + // check for reserved data frame opcodes + if (!(frameOpcode == OPCODE_CONT || frameOpcode == OPCODE_TEXT + || frameOpcode == OPCODE_BINARY)) { + protocolViolation(ctx, "data frame using reserved opcode " + frameOpcode); + return; + } - // Read frame payload length - if (framePayloadLen1 == 126) { - framePayloadLength = in.readUnsignedShort(); - if (framePayloadLength < 126) { - protocolViolation(ctx, "invalid data frame length (not using minimal length encoding)"); - return; - } - } else if (framePayloadLen1 == 127) { - framePayloadLength = in.readLong(); - // TODO: check if it's bigger than 0x7FFFFFFFFFFFFFFF, Maybe - // just check if it's negative? + // check opcode vs message fragmentation state 1/2 + if (fragmentedFramesCount == 0 && frameOpcode == OPCODE_CONT) { + protocolViolation(ctx, "received continuation data frame outside fragmented message"); + return; + } - if (framePayloadLength < 65536) { - protocolViolation(ctx, "invalid data frame length (not using minimal length encoding)"); - return; - } - } else { - framePayloadLength = framePayloadLen1; - } - - if (framePayloadLength > maxFramePayloadLength) { - protocolViolation(ctx, "Max frame length of " + maxFramePayloadLength + " has been exceeded."); - return; - } - - if (logger.isDebugEnabled()) { - logger.debug("Decoding WebSocket Frame length={}", framePayloadLength); - } - - checkpoint(State.MASKING_KEY); - case MASKING_KEY: - if (maskedPayload) { - maskingKey = in.readBytes(4); - } - checkpoint(State.PAYLOAD); - case PAYLOAD: - // Sometimes, the payload may not be delivered in 1 nice packet - // We need to accumulate the data until we have it all - int rbytes = actualReadableBytes(); - ByteBuf payloadBuffer = null; - - long willHaveReadByteCount = framePayloadBytesRead + rbytes; - // logger.debug("Frame rbytes=" + rbytes + " willHaveReadByteCount=" - // + willHaveReadByteCount + " framePayloadLength=" + - // framePayloadLength); - if (willHaveReadByteCount == framePayloadLength) { - // We have all our content so proceed to process - payloadBuffer = ctx.alloc().buffer(rbytes); - payloadBuffer.writeBytes(in, rbytes); - } else if (willHaveReadByteCount < framePayloadLength) { - - // We don't have all our content so accumulate payload. - // Returning null means we will get called back - if (framePayload == null) { - framePayload = ctx.alloc().buffer(toFrameLength(framePayloadLength)); - } - framePayload.writeBytes(in, rbytes); - framePayloadBytesRead += rbytes; - - // Return null to wait for more bytes to arrive - return; - } else if (willHaveReadByteCount > framePayloadLength) { - // We have more than what we need so read up to the end of frame - // Leave the remainder in the buffer for next frame - if (framePayload == null) { - framePayload = ctx.alloc().buffer(toFrameLength(framePayloadLength)); - } - framePayload.writeBytes(in, toFrameLength(framePayloadLength - framePayloadBytesRead)); - } - - // Now we have all the data, the next checkpoint must be the next - // frame - checkpoint(State.FRAME_START); - - // Take the data that we have in this packet - if (framePayload == null) { - framePayload = payloadBuffer; - } else if (payloadBuffer != null) { - framePayload.writeBytes(payloadBuffer); - } - - // Unmask data if needed - if (maskedPayload) { - unmask(framePayload); - } - - // Processing ping/pong/close frames because they cannot be - // fragmented - if (frameOpcode == OPCODE_PING) { - out.add(new PingWebSocketFrame(frameFinalFlag, frameRsv, framePayload)); - return; - } - if (frameOpcode == OPCODE_PONG) { - out.add(new PongWebSocketFrame(frameFinalFlag, frameRsv, framePayload)); - return; - } - if (frameOpcode == OPCODE_CLOSE) { - checkCloseFrameBody(ctx, framePayload); - receivedClosingHandshake = true; - out.add(new CloseWebSocketFrame(frameFinalFlag, frameRsv, framePayload)); - return; - } - - // Processing for possible fragmented messages for text and binary - // frames - String aggregatedText = null; - if (frameFinalFlag) { - // Final frame of the sequence. Apparently ping frames are - // allowed in the middle of a fragmented message - if (frameOpcode != OPCODE_PING) { - fragmentedFramesCount = 0; - - // Check text for UTF8 correctness - if (frameOpcode == OPCODE_TEXT || fragmentedFramesText != null) { - // Check UTF-8 correctness for this payload - checkUTF8String(ctx, framePayload); - - // This does a second check to make sure UTF-8 - // correctness for entire text message - aggregatedText = fragmentedFramesText.toString(); - - fragmentedFramesText = null; + // check opcode vs message fragmentation state 2/2 + if (fragmentedFramesCount != 0 && frameOpcode != OPCODE_CONT && frameOpcode != OPCODE_PING) { + protocolViolation(ctx, + "received non-continuation data frame while inside fragmented message"); + return; } } - } else { - // Not final frame so we can expect more frames in the - // fragmented sequence - if (fragmentedFramesCount == 0) { - // First text or binary frame for a fragmented set - fragmentedFramesText = null; - if (frameOpcode == OPCODE_TEXT) { - checkUTF8String(ctx, framePayload); + + // Read frame payload length + if (framePayloadLen1 == 126) { + framePayloadLength = in.readUnsignedShort(); + if (framePayloadLength < 126) { + protocolViolation(ctx, "invalid data frame length (not using minimal length encoding)"); + return; + } + } else if (framePayloadLen1 == 127) { + framePayloadLength = in.readLong(); + // TODO: check if it's bigger than 0x7FFFFFFFFFFFFFFF, Maybe + // just check if it's negative? + + if (framePayloadLength < 65536) { + protocolViolation(ctx, "invalid data frame length (not using minimal length encoding)"); + return; } } else { - // Subsequent frames - only check if init frame is text - if (fragmentedFramesText != null) { - checkUTF8String(ctx, framePayload); - } + framePayloadLength = framePayloadLen1; } - // Increment counter - fragmentedFramesCount++; - } + if (framePayloadLength > maxFramePayloadLength) { + protocolViolation(ctx, "Max frame length of " + maxFramePayloadLength + " has been exceeded."); + return; + } - // Return the frame - if (frameOpcode == OPCODE_TEXT) { - out.add(new TextWebSocketFrame(frameFinalFlag, frameRsv, framePayload)); + if (logger.isDebugEnabled()) { + logger.debug("Decoding WebSocket Frame length={}", framePayloadLength); + } + + checkpoint(State.MASKING_KEY); + case MASKING_KEY: + if (maskedPayload) { + maskingKey = in.readBytes(4); + } + checkpoint(State.PAYLOAD); + case PAYLOAD: + // Sometimes, the payload may not be delivered in 1 nice packet + // We need to accumulate the data until we have it all + int rbytes = actualReadableBytes(); + + long willHaveReadByteCount = framePayloadBytesRead + rbytes; + // logger.debug("Frame rbytes=" + rbytes + " willHaveReadByteCount=" + // + willHaveReadByteCount + " framePayloadLength=" + + // framePayloadLength); + if (willHaveReadByteCount == framePayloadLength) { + // We have all our content so proceed to process + payloadBuffer = ctx.alloc().buffer(rbytes); + payloadBuffer.writeBytes(in, rbytes); + } else if (willHaveReadByteCount < framePayloadLength) { + + // We don't have all our content so accumulate payload. + // Returning null means we will get called back + if (framePayload == null) { + framePayload = ctx.alloc().buffer(toFrameLength(framePayloadLength)); + } + framePayload.writeBytes(in, rbytes); + framePayloadBytesRead += rbytes; + + // Return null to wait for more bytes to arrive + return; + } else if (willHaveReadByteCount > framePayloadLength) { + // We have more than what we need so read up to the end of frame + // Leave the remainder in the buffer for next frame + if (framePayload == null) { + framePayload = ctx.alloc().buffer(toFrameLength(framePayloadLength)); + } + framePayload.writeBytes(in, toFrameLength(framePayloadLength - framePayloadBytesRead)); + } + + // Now we have all the data, the next checkpoint must be the next + // frame + checkpoint(State.FRAME_START); + + // Take the data that we have in this packet + if (framePayload == null) { + framePayload = payloadBuffer; + } else if (payloadBuffer != null) { + framePayload.writeBytes(payloadBuffer); + } + + // Unmask data if needed + if (maskedPayload) { + unmask(framePayload); + } + + // Processing ping/pong/close frames because they cannot be + // fragmented + if (frameOpcode == OPCODE_PING) { + out.add(new PingWebSocketFrame(frameFinalFlag, frameRsv, framePayload)); + return; + } + if (frameOpcode == OPCODE_PONG) { + out.add(new PongWebSocketFrame(frameFinalFlag, frameRsv, framePayload)); + return; + } + if (frameOpcode == OPCODE_CLOSE) { + checkCloseFrameBody(ctx, framePayload); + receivedClosingHandshake = true; + out.add(new CloseWebSocketFrame(frameFinalFlag, frameRsv, framePayload)); + return; + } + + // Processing for possible fragmented messages for text and binary + // frames + String aggregatedText = null; + if (frameFinalFlag) { + // Final frame of the sequence. Apparently ping frames are + // allowed in the middle of a fragmented message + if (frameOpcode != OPCODE_PING) { + fragmentedFramesCount = 0; + + // Check text for UTF8 correctness + if (frameOpcode == OPCODE_TEXT || fragmentedFramesText != null) { + // Check UTF-8 correctness for this payload + checkUTF8String(ctx, framePayload); + + // This does a second check to make sure UTF-8 + // correctness for entire text message + aggregatedText = fragmentedFramesText.toString(); + + fragmentedFramesText = null; + } + } + } else { + // Not final frame so we can expect more frames in the + // fragmented sequence + if (fragmentedFramesCount == 0) { + // First text or binary frame for a fragmented set + fragmentedFramesText = null; + if (frameOpcode == OPCODE_TEXT) { + checkUTF8String(ctx, framePayload); + } + } else { + // Subsequent frames - only check if init frame is text + if (fragmentedFramesText != null) { + checkUTF8String(ctx, framePayload); + } + } + + // Increment counter + fragmentedFramesCount++; + } + + // Return the frame + if (frameOpcode == OPCODE_TEXT) { + out.add(new TextWebSocketFrame(frameFinalFlag, frameRsv, framePayload)); + return; + } else if (frameOpcode == OPCODE_BINARY) { + out.add(new BinaryWebSocketFrame(frameFinalFlag, frameRsv, framePayload)); + return; + } else if (frameOpcode == OPCODE_CONT) { + out.add(new ContinuationWebSocketFrame(frameFinalFlag, frameRsv, framePayload, aggregatedText)); + return; + } else { + throw new UnsupportedOperationException("Cannot decode web socket frame with opcode: " + + frameOpcode); + } + case CORRUPT: + // If we don't keep reading Netty will throw an exception saying + // we can't return null if no bytes read and state not changed. + in.readByte(); return; - } else if (frameOpcode == OPCODE_BINARY) { - out.add(new BinaryWebSocketFrame(frameFinalFlag, frameRsv, framePayload)); - return; - } else if (frameOpcode == OPCODE_CONT) { - out.add(new ContinuationWebSocketFrame(frameFinalFlag, frameRsv, framePayload, aggregatedText)); - return; - } else { - throw new UnsupportedOperationException("Cannot decode web socket frame with opcode: " - + frameOpcode); + default: + throw new Error("Shouldn't reach here."); + } + } catch (Exception e) { + if (payloadBuffer != null) { + if (payloadBuffer.refCnt() > 0) { + payloadBuffer.release(); } - case CORRUPT: - // If we don't keep reading Netty will throw an exception saying - // we can't return null if no bytes read and state not changed. - in.readByte(); - return; - default: - throw new Error("Shouldn't reach here."); + payloadBuffer = null; + } + if (framePayload != null) { + if (framePayload.refCnt() > 0) { + framePayload.release(); + } + framePayload = null; + } + throw e; } } @@ -380,7 +401,7 @@ public class WebSocket08FrameDecoder extends ReplayingDecoder newWebSocketEncoder(); + protected abstract ChannelOutboundHandler newWebSocketEncoder(); } diff --git a/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketClientHandshaker00.java b/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketClientHandshaker00.java index 4fc2211625..b8422ac00c 100644 --- a/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketClientHandshaker00.java +++ b/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketClientHandshaker00.java @@ -17,8 +17,8 @@ package io.netty.handler.codec.http.websocketx; import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; -import io.netty.channel.ChannelInboundByteHandler; -import io.netty.channel.ChannelOutboundMessageHandler; +import io.netty.channel.ChannelInboundHandler; +import io.netty.channel.ChannelOutboundHandler; import io.netty.handler.codec.http.DefaultFullHttpRequest; import io.netty.handler.codec.http.FullHttpRequest; import io.netty.handler.codec.http.FullHttpResponse; @@ -252,12 +252,12 @@ public class WebSocketClientHandshaker00 extends WebSocketClientHandshaker { } @Override - protected ChannelInboundByteHandler newWebsocketDecoder() { + protected ChannelInboundHandler newWebsocketDecoder() { return new WebSocket00FrameDecoder(maxFramePayloadLength()); } @Override - protected ChannelOutboundMessageHandler newWebSocketEncoder() { + protected ChannelOutboundHandler newWebSocketEncoder() { return new WebSocket00FrameEncoder(); } } diff --git a/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketClientHandshaker07.java b/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketClientHandshaker07.java index 205ba762fe..b85c654696 100644 --- a/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketClientHandshaker07.java +++ b/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketClientHandshaker07.java @@ -15,8 +15,8 @@ */ package io.netty.handler.codec.http.websocketx; -import io.netty.channel.ChannelInboundByteHandler; -import io.netty.channel.ChannelOutboundMessageHandler; +import io.netty.channel.ChannelInboundHandler; +import io.netty.channel.ChannelOutboundHandler; import io.netty.handler.codec.http.DefaultFullHttpRequest; import io.netty.handler.codec.http.FullHttpRequest; import io.netty.handler.codec.http.FullHttpResponse; @@ -191,12 +191,12 @@ public class WebSocketClientHandshaker07 extends WebSocketClientHandshaker { } @Override - protected ChannelInboundByteHandler newWebsocketDecoder() { + protected ChannelInboundHandler newWebsocketDecoder() { return new WebSocket07FrameDecoder(false, allowExtensions, maxFramePayloadLength()); } @Override - protected ChannelOutboundMessageHandler newWebSocketEncoder() { + protected ChannelOutboundHandler newWebSocketEncoder() { return new WebSocket07FrameEncoder(true); } } diff --git a/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketClientHandshaker08.java b/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketClientHandshaker08.java index bb66d369b6..93b2132aa2 100644 --- a/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketClientHandshaker08.java +++ b/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketClientHandshaker08.java @@ -15,8 +15,8 @@ */ package io.netty.handler.codec.http.websocketx; -import io.netty.channel.ChannelInboundByteHandler; -import io.netty.channel.ChannelOutboundMessageHandler; +import io.netty.channel.ChannelInboundHandler; +import io.netty.channel.ChannelOutboundHandler; import io.netty.handler.codec.http.DefaultFullHttpRequest; import io.netty.handler.codec.http.FullHttpRequest; import io.netty.handler.codec.http.FullHttpResponse; @@ -191,12 +191,12 @@ public class WebSocketClientHandshaker08 extends WebSocketClientHandshaker { } @Override - protected ChannelInboundByteHandler newWebsocketDecoder() { + protected ChannelInboundHandler newWebsocketDecoder() { return new WebSocket08FrameDecoder(false, allowExtensions, maxFramePayloadLength()); } @Override - protected ChannelOutboundMessageHandler newWebSocketEncoder() { + protected ChannelOutboundHandler newWebSocketEncoder() { return new WebSocket08FrameEncoder(true); } } diff --git a/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketClientHandshaker13.java b/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketClientHandshaker13.java index 9f2c4ca336..b12ac03dde 100644 --- a/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketClientHandshaker13.java +++ b/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketClientHandshaker13.java @@ -15,8 +15,8 @@ */ package io.netty.handler.codec.http.websocketx; -import io.netty.channel.ChannelInboundByteHandler; -import io.netty.channel.ChannelOutboundMessageHandler; +import io.netty.channel.ChannelInboundHandler; +import io.netty.channel.ChannelOutboundHandler; import io.netty.handler.codec.http.DefaultFullHttpRequest; import io.netty.handler.codec.http.FullHttpRequest; import io.netty.handler.codec.http.FullHttpResponse; @@ -191,12 +191,12 @@ public class WebSocketClientHandshaker13 extends WebSocketClientHandshaker { } @Override - protected ChannelInboundByteHandler newWebsocketDecoder() { + protected ChannelInboundHandler newWebsocketDecoder() { return new WebSocket13FrameDecoder(false, allowExtensions, maxFramePayloadLength()); } @Override - protected ChannelOutboundMessageHandler newWebSocketEncoder() { + protected ChannelOutboundHandler newWebSocketEncoder() { return new WebSocket13FrameEncoder(true); } } diff --git a/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketClientProtocolHandler.java b/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketClientProtocolHandler.java index a3d72ab96d..69d5af599f 100644 --- a/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketClientProtocolHandler.java +++ b/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketClientProtocolHandler.java @@ -16,8 +16,9 @@ package io.netty.handler.codec.http.websocketx; import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.ChannelInboundHandler; import io.netty.channel.ChannelPipeline; -import io.netty.channel.ChannelStateHandler; +import io.netty.channel.MessageList; import io.netty.handler.codec.http.HttpHeaders; import java.net.URI; @@ -33,7 +34,7 @@ import java.net.URI; * This implementation will establish the websocket connection once the connection to the remote server was complete. * * To know once a handshake was done you can intercept the - * {@link ChannelStateHandler#userEventTriggered(ChannelHandlerContext, Object)} and check if the event was of type + * {@link ChannelInboundHandler#userEventTriggered(ChannelHandlerContext, Object)} and check if the event was of type * {@link ClientHandshakeStateEvent#HANDSHAKE_ISSUED} or {@link ClientHandshakeStateEvent#HANDSHAKE_COMPLETE}. */ public class WebSocketClientProtocolHandler extends WebSocketProtocolHandler { @@ -128,12 +129,12 @@ public class WebSocketClientProtocolHandler extends WebSocketProtocolHandler { } @Override - public void messageReceived(ChannelHandlerContext ctx, WebSocketFrame frame) throws Exception { + protected void decode(ChannelHandlerContext ctx, WebSocketFrame frame, MessageList out) throws Exception { if (handleCloseFrames && frame instanceof CloseWebSocketFrame) { ctx.close(); return; } - super.messageReceived(ctx, frame); + super.decode(ctx, frame, out); } @Override diff --git a/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketClientProtocolHandshakeHandler.java b/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketClientProtocolHandshakeHandler.java index 6ba95fa736..56c3b62967 100644 --- a/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketClientProtocolHandshakeHandler.java +++ b/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketClientProtocolHandshakeHandler.java @@ -18,10 +18,11 @@ package io.netty.handler.codec.http.websocketx; import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelFutureListener; import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.ChannelInboundMessageHandlerAdapter; +import io.netty.channel.ChannelInboundHandlerAdapter; +import io.netty.channel.MessageList; import io.netty.handler.codec.http.FullHttpResponse; -class WebSocketClientProtocolHandshakeHandler extends ChannelInboundMessageHandlerAdapter { +class WebSocketClientProtocolHandshakeHandler extends ChannelInboundHandlerAdapter { private final WebSocketClientHandshaker handshaker; public WebSocketClientProtocolHandshakeHandler(WebSocketClientHandshaker handshaker) { @@ -45,9 +46,10 @@ class WebSocketClientProtocolHandshakeHandler extends ChannelInboundMessageHandl } @Override - public void messageReceived(ChannelHandlerContext ctx, FullHttpResponse msg) throws Exception { + public void messageReceived(ChannelHandlerContext ctx, MessageList messages) throws Exception { if (!handshaker.isHandshakeComplete()) { - handshaker.finishHandshake(ctx.channel(), msg); + handshaker.finishHandshake(ctx.channel(), (FullHttpResponse) messages.get(0)); + messages.remove(0); ctx.fireUserEventTriggered( WebSocketClientProtocolHandler.ClientHandshakeStateEvent.HANDSHAKE_COMPLETE); ctx.pipeline().remove(this); diff --git a/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketFrameAggregator.java b/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketFrameAggregator.java index 0ff0b28ba0..739ff18e2f 100644 --- a/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketFrameAggregator.java +++ b/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketFrameAggregator.java @@ -17,8 +17,8 @@ package io.netty.handler.codec.http.websocketx; import io.netty.buffer.ByteBuf; import io.netty.buffer.CompositeByteBuf; -import io.netty.buffer.MessageBuf; import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.MessageList; import io.netty.handler.codec.MessageToMessageDecoder; import io.netty.handler.codec.TooLongFrameException; @@ -47,7 +47,7 @@ public class WebSocketFrameAggregator extends MessageToMessageDecoder out) throws Exception { + protected void decode(ChannelHandlerContext ctx, WebSocketFrame msg, MessageList out) throws Exception { if (currentFrame == null) { tooLongFrameFound = false; if (msg.isFinalFragment()) { diff --git a/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketProtocolHandler.java b/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketProtocolHandler.java index c5014ba6d7..49ca45ec86 100644 --- a/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketProtocolHandler.java +++ b/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketProtocolHandler.java @@ -17,12 +17,12 @@ package io.netty.handler.codec.http.websocketx; import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.ChannelInboundMessageHandlerAdapter; - -abstract class WebSocketProtocolHandler extends ChannelInboundMessageHandlerAdapter { +import io.netty.channel.MessageList; +import io.netty.handler.codec.MessageToMessageDecoder; +abstract class WebSocketProtocolHandler extends MessageToMessageDecoder { @Override - public void messageReceived(ChannelHandlerContext ctx, WebSocketFrame frame) throws Exception { + protected void decode(ChannelHandlerContext ctx, WebSocketFrame frame, MessageList out) throws Exception { if (frame instanceof PingWebSocketFrame) { frame.content().retain(); ctx.channel().write(new PongWebSocketFrame(frame.content())); @@ -33,8 +33,7 @@ abstract class WebSocketProtocolHandler extends ChannelInboundMessageHandlerAda return; } - frame.retain(); - ctx.nextInboundMessageBuffer().add(frame); + out.add(frame.retain()); } @Override diff --git a/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketServerHandshaker.java b/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketServerHandshaker.java index 38d00d0389..de8c88fdfe 100644 --- a/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketServerHandshaker.java +++ b/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketServerHandshaker.java @@ -19,8 +19,8 @@ import io.netty.channel.Channel; import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelFutureListener; import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.ChannelInboundByteHandler; -import io.netty.channel.ChannelOutboundMessageHandler; +import io.netty.channel.ChannelInboundHandler; +import io.netty.channel.ChannelOutboundHandler; import io.netty.channel.ChannelPipeline; import io.netty.channel.ChannelPromise; import io.netty.handler.codec.http.FullHttpRequest; @@ -267,11 +267,11 @@ public abstract class WebSocketServerHandshaker { /** * Returns the decoder to use after handshake is complete. */ - protected abstract ChannelInboundByteHandler newWebsocketDecoder(); + protected abstract ChannelInboundHandler newWebsocketDecoder(); /** * Returns the encoder to use after the handshake is complete. */ - protected abstract ChannelOutboundMessageHandler newWebSocketEncoder(); + protected abstract ChannelOutboundHandler newWebSocketEncoder(); } diff --git a/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketServerHandshaker00.java b/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketServerHandshaker00.java index 89969fde68..73307000e3 100644 --- a/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketServerHandshaker00.java +++ b/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketServerHandshaker00.java @@ -19,8 +19,8 @@ import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import io.netty.channel.Channel; import io.netty.channel.ChannelFuture; -import io.netty.channel.ChannelInboundByteHandler; -import io.netty.channel.ChannelOutboundMessageHandler; +import io.netty.channel.ChannelInboundHandler; +import io.netty.channel.ChannelOutboundHandler; import io.netty.channel.ChannelPromise; import io.netty.handler.codec.http.DefaultFullHttpResponse; import io.netty.handler.codec.http.FullHttpRequest; @@ -183,12 +183,12 @@ public class WebSocketServerHandshaker00 extends WebSocketServerHandshaker { } @Override - protected ChannelInboundByteHandler newWebsocketDecoder() { + protected ChannelInboundHandler newWebsocketDecoder() { return new WebSocket00FrameDecoder(maxFramePayloadLength()); } @Override - protected ChannelOutboundMessageHandler newWebSocketEncoder() { + protected ChannelOutboundHandler newWebSocketEncoder() { return new WebSocket00FrameEncoder(); } } diff --git a/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketServerHandshaker07.java b/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketServerHandshaker07.java index 514dd1a12b..e7b76de3a7 100644 --- a/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketServerHandshaker07.java +++ b/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketServerHandshaker07.java @@ -15,8 +15,8 @@ */ package io.netty.handler.codec.http.websocketx; -import io.netty.channel.ChannelInboundByteHandler; -import io.netty.channel.ChannelOutboundMessageHandler; +import io.netty.channel.ChannelInboundHandler; +import io.netty.channel.ChannelOutboundHandler; import io.netty.handler.codec.http.DefaultFullHttpResponse; import io.netty.handler.codec.http.FullHttpRequest; import io.netty.handler.codec.http.FullHttpResponse; @@ -132,12 +132,12 @@ public class WebSocketServerHandshaker07 extends WebSocketServerHandshaker { } @Override - protected ChannelInboundByteHandler newWebsocketDecoder() { + protected ChannelInboundHandler newWebsocketDecoder() { return new WebSocket07FrameDecoder(true, allowExtensions, maxFramePayloadLength()); } @Override - protected ChannelOutboundMessageHandler newWebSocketEncoder() { + protected ChannelOutboundHandler newWebSocketEncoder() { return new WebSocket07FrameEncoder(false); } } diff --git a/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketServerHandshaker08.java b/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketServerHandshaker08.java index d465b81f18..98bc9dd800 100644 --- a/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketServerHandshaker08.java +++ b/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketServerHandshaker08.java @@ -15,8 +15,8 @@ */ package io.netty.handler.codec.http.websocketx; -import io.netty.channel.ChannelInboundByteHandler; -import io.netty.channel.ChannelOutboundMessageHandler; +import io.netty.channel.ChannelInboundHandler; +import io.netty.channel.ChannelOutboundHandler; import io.netty.handler.codec.http.DefaultFullHttpResponse; import io.netty.handler.codec.http.FullHttpRequest; import io.netty.handler.codec.http.FullHttpResponse; @@ -131,12 +131,12 @@ public class WebSocketServerHandshaker08 extends WebSocketServerHandshaker { } @Override - protected ChannelInboundByteHandler newWebsocketDecoder() { + protected ChannelInboundHandler newWebsocketDecoder() { return new WebSocket08FrameDecoder(true, allowExtensions, maxFramePayloadLength()); } @Override - protected ChannelOutboundMessageHandler newWebSocketEncoder() { + protected ChannelOutboundHandler newWebSocketEncoder() { return new WebSocket08FrameEncoder(false); } } diff --git a/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketServerHandshaker13.java b/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketServerHandshaker13.java index 470fb86dd9..611294adde 100644 --- a/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketServerHandshaker13.java +++ b/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketServerHandshaker13.java @@ -15,8 +15,8 @@ */ package io.netty.handler.codec.http.websocketx; -import io.netty.channel.ChannelInboundByteHandler; -import io.netty.channel.ChannelOutboundMessageHandler; +import io.netty.channel.ChannelInboundHandler; +import io.netty.channel.ChannelOutboundHandler; import io.netty.handler.codec.http.DefaultFullHttpResponse; import io.netty.handler.codec.http.FullHttpRequest; import io.netty.handler.codec.http.FullHttpResponse; @@ -130,12 +130,12 @@ public class WebSocketServerHandshaker13 extends WebSocketServerHandshaker { } @Override - protected ChannelInboundByteHandler newWebsocketDecoder() { + protected ChannelInboundHandler newWebsocketDecoder() { return new WebSocket13FrameDecoder(true, allowExtensions, maxFramePayloadLength()); } @Override - protected ChannelOutboundMessageHandler newWebSocketEncoder() { + protected ChannelOutboundHandler newWebSocketEncoder() { return new WebSocket13FrameEncoder(false); } } diff --git a/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketServerProtocolHandler.java b/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketServerProtocolHandler.java index aad5f9be07..449444cc37 100644 --- a/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketServerProtocolHandler.java +++ b/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketServerProtocolHandler.java @@ -19,9 +19,10 @@ import io.netty.buffer.Unpooled; import io.netty.channel.ChannelFutureListener; import io.netty.channel.ChannelHandler; import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.ChannelInboundMessageHandlerAdapter; -import io.netty.channel.ChannelStateHandler; +import io.netty.channel.ChannelInboundHandler; +import io.netty.channel.ChannelInboundHandlerAdapter; import io.netty.channel.ChannelPipeline; +import io.netty.channel.MessageList; import io.netty.handler.codec.http.DefaultFullHttpResponse; import io.netty.handler.codec.http.FullHttpRequest; import io.netty.handler.codec.http.FullHttpResponse; @@ -43,7 +44,7 @@ import static io.netty.handler.codec.http.HttpVersion.*; * to the io.netty.example.http.websocketx.server.WebSocketServer example. * * To know once a handshake was done you can intercept the - * {@link ChannelStateHandler#userEventTriggered(ChannelHandlerContext, Object)} and check if the event was of type + * {@link ChannelInboundHandler#userEventTriggered(ChannelHandlerContext, Object)} and check if the event was of type * {@link ServerHandshakeStateEvent#HANDSHAKE_COMPLETE}. */ public class WebSocketServerProtocolHandler extends WebSocketProtocolHandler { @@ -90,14 +91,14 @@ public class WebSocketServerProtocolHandler extends WebSocketProtocolHandler { } @Override - public void messageReceived(ChannelHandlerContext ctx, WebSocketFrame frame) throws Exception { + protected void decode(ChannelHandlerContext ctx, WebSocketFrame frame, MessageList out) throws Exception { if (frame instanceof CloseWebSocketFrame) { WebSocketServerHandshaker handshaker = getHandshaker(ctx); frame.retain(); handshaker.close(ctx.channel(), (CloseWebSocketFrame) frame); return; } - super.messageReceived(ctx, frame); + super.decode(ctx, frame, out); } @Override @@ -120,12 +121,19 @@ public class WebSocketServerProtocolHandler extends WebSocketProtocolHandler { } static ChannelHandler forbiddenHttpRequestResponder() { - return new ChannelInboundMessageHandlerAdapter() { + return new ChannelInboundHandlerAdapter() { @Override - public void messageReceived(ChannelHandlerContext ctx, FullHttpRequest msg) throws Exception { - FullHttpResponse response = - new DefaultFullHttpResponse(HTTP_1_1, HttpResponseStatus.FORBIDDEN); - ctx.channel().write(response); + public void messageReceived(final ChannelHandlerContext ctx, MessageList msgs) throws Exception { + for (int i = 0; i < msgs.size(); i++) { + Object msg = msgs.get(i); + if (msg instanceof FullHttpRequest) { + FullHttpResponse response = + new DefaultFullHttpResponse(HTTP_1_1, HttpResponseStatus.FORBIDDEN); + ctx.channel().write(response); + msgs.remove(i--); + } + } + ctx.fireMessageReceived(msgs); } }; } diff --git a/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketServerProtocolHandshakeHandler.java b/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketServerProtocolHandshakeHandler.java index c30fff92e4..31e4ada4ee 100644 --- a/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketServerProtocolHandshakeHandler.java +++ b/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketServerProtocolHandshakeHandler.java @@ -18,8 +18,9 @@ package io.netty.handler.codec.http.websocketx; import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelFutureListener; import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.ChannelInboundMessageHandlerAdapter; +import io.netty.channel.ChannelInboundHandlerAdapter; import io.netty.channel.ChannelPipeline; +import io.netty.channel.MessageList; import io.netty.handler.codec.http.DefaultFullHttpResponse; import io.netty.handler.codec.http.FullHttpRequest; import io.netty.handler.codec.http.HttpHeaders; @@ -36,7 +37,7 @@ import static io.netty.handler.codec.http.HttpVersion.*; * Handles the HTTP handshake (the HTTP Upgrade request) for {@link WebSocketServerProtocolHandler}. */ class WebSocketServerProtocolHandshakeHandler - extends ChannelInboundMessageHandlerAdapter { + extends ChannelInboundHandlerAdapter { private final String websocketPath; private final String subprotocols; @@ -50,33 +51,37 @@ class WebSocketServerProtocolHandshakeHandler } @Override - public void messageReceived(final ChannelHandlerContext ctx, FullHttpRequest req) throws Exception { - if (req.getMethod() != GET) { - sendHttpResponse(ctx, req, new DefaultFullHttpResponse(HTTP_1_1, FORBIDDEN)); - return; - } + public void messageReceived(final ChannelHandlerContext ctx, MessageList msgs) throws Exception { + MessageList requests = msgs.cast(); + for (int i = 0; i < requests.size(); i++) { + FullHttpRequest req = requests.get(i); + if (req.getMethod() != GET) { + sendHttpResponse(ctx, req, new DefaultFullHttpResponse(HTTP_1_1, FORBIDDEN)); + return; + } - final WebSocketServerHandshakerFactory wsFactory = new WebSocketServerHandshakerFactory( - getWebSocketLocation(ctx.pipeline(), req, websocketPath), subprotocols, allowExtensions); - final WebSocketServerHandshaker handshaker = wsFactory.newHandshaker(req); - if (handshaker == null) { - WebSocketServerHandshakerFactory.sendUnsupportedWebSocketVersionResponse(ctx.channel()); - } else { - final ChannelFuture handshakeFuture = handshaker.handshake(ctx.channel(), req); - handshakeFuture.addListener(new ChannelFutureListener() { - @Override - public void operationComplete(ChannelFuture future) throws Exception { - if (!future.isSuccess()) { - ctx.fireExceptionCaught(future.cause()); - } else { - ctx.fireUserEventTriggered( - WebSocketServerProtocolHandler.ServerHandshakeStateEvent.HANDSHAKE_COMPLETE); + final WebSocketServerHandshakerFactory wsFactory = new WebSocketServerHandshakerFactory( + getWebSocketLocation(ctx.pipeline(), req, websocketPath), subprotocols, allowExtensions); + final WebSocketServerHandshaker handshaker = wsFactory.newHandshaker(req); + if (handshaker == null) { + WebSocketServerHandshakerFactory.sendUnsupportedWebSocketVersionResponse(ctx.channel()); + } else { + final ChannelFuture handshakeFuture = handshaker.handshake(ctx.channel(), req); + handshakeFuture.addListener(new ChannelFutureListener() { + @Override + public void operationComplete(ChannelFuture future) throws Exception { + if (!future.isSuccess()) { + ctx.fireExceptionCaught(future.cause()); + } else { + ctx.fireUserEventTriggered( + WebSocketServerProtocolHandler.ServerHandshakeStateEvent.HANDSHAKE_COMPLETE); + } } - } - }); - WebSocketServerProtocolHandler.setHandshaker(ctx, handshaker); - ctx.pipeline().replace(this, "WS403Responder", - WebSocketServerProtocolHandler.forbiddenHttpRequestResponder()); + }); + WebSocketServerProtocolHandler.setHandshaker(ctx, handshaker); + ctx.pipeline().replace(this, "WS403Responder", + WebSocketServerProtocolHandler.forbiddenHttpRequestResponder()); + } } } diff --git a/codec-http/src/main/java/io/netty/handler/codec/spdy/SpdyFrameCodec.java b/codec-http/src/main/java/io/netty/handler/codec/spdy/SpdyFrameCodec.java index 67b73b1fad..d18952f6fb 100644 --- a/codec-http/src/main/java/io/netty/handler/codec/spdy/SpdyFrameCodec.java +++ b/codec-http/src/main/java/io/netty/handler/codec/spdy/SpdyFrameCodec.java @@ -15,20 +15,12 @@ */ package io.netty.handler.codec.spdy; -import io.netty.buffer.ByteBuf; -import io.netty.buffer.MessageBuf; -import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.ChannelInboundByteHandler; -import io.netty.channel.ChannelOutboundMessageHandler; import io.netty.channel.CombinedChannelDuplexHandler; - /** * A combination of {@link SpdyFrameDecoder} and {@link SpdyFrameEncoder}. */ -public final class SpdyFrameCodec - extends CombinedChannelDuplexHandler - implements ChannelInboundByteHandler, ChannelOutboundMessageHandler { +public final class SpdyFrameCodec extends CombinedChannelDuplexHandler { /** * Creates a new instance with the specified {@code version} and @@ -51,27 +43,4 @@ public final class SpdyFrameCodec new SpdyFrameDecoder(version, maxChunkSize, maxHeaderSize), new SpdyFrameEncoder(version, compressionLevel, windowBits, memLevel)); } - - private SpdyFrameDecoder decoder() { - return (SpdyFrameDecoder) stateHandler(); - } - - private SpdyFrameEncoder encoder() { - return (SpdyFrameEncoder) operationHandler(); - } - - @Override - public ByteBuf newInboundBuffer(ChannelHandlerContext ctx) throws Exception { - return decoder().newInboundBuffer(ctx); - } - - @Override - public void discardInboundReadBytes(ChannelHandlerContext ctx) throws Exception { - decoder().discardInboundReadBytes(ctx); - } - - @Override - public MessageBuf newOutboundBuffer(ChannelHandlerContext ctx) throws Exception { - return encoder().newOutboundBuffer(ctx); - } } diff --git a/codec-http/src/main/java/io/netty/handler/codec/spdy/SpdyFrameDecoder.java b/codec-http/src/main/java/io/netty/handler/codec/spdy/SpdyFrameDecoder.java index 6a0de974d1..4147f5ac5d 100644 --- a/codec-http/src/main/java/io/netty/handler/codec/spdy/SpdyFrameDecoder.java +++ b/codec-http/src/main/java/io/netty/handler/codec/spdy/SpdyFrameDecoder.java @@ -16,9 +16,9 @@ package io.netty.handler.codec.spdy; import io.netty.buffer.ByteBuf; -import io.netty.buffer.MessageBuf; import io.netty.buffer.Unpooled; import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.MessageList; import io.netty.handler.codec.ByteToMessageDecoder; import io.netty.handler.codec.TooLongFrameException; @@ -94,7 +94,7 @@ public class SpdyFrameDecoder extends ByteToMessageDecoder { } @Override - public void decodeLast(ChannelHandlerContext ctx, ByteBuf in, MessageBuf out) throws Exception { + public void decodeLast(ChannelHandlerContext ctx, ByteBuf in, MessageList out) throws Exception { try { decode(ctx, in, out); } finally { @@ -103,7 +103,7 @@ public class SpdyFrameDecoder extends ByteToMessageDecoder { } @Override - protected void decode(ChannelHandlerContext ctx, ByteBuf buffer, MessageBuf out) throws Exception { + protected void decode(ChannelHandlerContext ctx, ByteBuf buffer, MessageList out) throws Exception { switch(state) { case READ_COMMON_HEADER: state = readCommonHeader(buffer); diff --git a/codec-http/src/main/java/io/netty/handler/codec/spdy/SpdyHttpCodec.java b/codec-http/src/main/java/io/netty/handler/codec/spdy/SpdyHttpCodec.java index cfb73bf528..562aef5b1c 100644 --- a/codec-http/src/main/java/io/netty/handler/codec/spdy/SpdyHttpCodec.java +++ b/codec-http/src/main/java/io/netty/handler/codec/spdy/SpdyHttpCodec.java @@ -15,20 +15,13 @@ */ package io.netty.handler.codec.spdy; -import io.netty.buffer.MessageBuf; -import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.ChannelInboundMessageHandler; -import io.netty.channel.ChannelOutboundMessageHandler; import io.netty.channel.CombinedChannelDuplexHandler; -import io.netty.handler.codec.http.HttpObject; - /** * A combination of {@link SpdyHttpDecoder} and {@link SpdyHttpEncoder} */ public final class SpdyHttpCodec - extends CombinedChannelDuplexHandler - implements ChannelInboundMessageHandler, ChannelOutboundMessageHandler { + extends CombinedChannelDuplexHandler { /** * Creates a new instance with the specified decoder options. @@ -36,22 +29,4 @@ public final class SpdyHttpCodec public SpdyHttpCodec(int version, int maxContentLength) { super(new SpdyHttpDecoder(version, maxContentLength), new SpdyHttpEncoder(version)); } - - private SpdyHttpDecoder decoder() { - return (SpdyHttpDecoder) stateHandler(); - } - - private SpdyHttpEncoder encoder() { - return (SpdyHttpEncoder) operationHandler(); - } - - @Override - public MessageBuf newInboundBuffer(ChannelHandlerContext ctx) throws Exception { - return decoder().newInboundBuffer(ctx); - } - - @Override - public MessageBuf newOutboundBuffer(ChannelHandlerContext ctx) throws Exception { - return encoder().newOutboundBuffer(ctx); - } } diff --git a/codec-http/src/main/java/io/netty/handler/codec/spdy/SpdyHttpDecoder.java b/codec-http/src/main/java/io/netty/handler/codec/spdy/SpdyHttpDecoder.java index ee0874f16a..e10fc2809c 100644 --- a/codec-http/src/main/java/io/netty/handler/codec/spdy/SpdyHttpDecoder.java +++ b/codec-http/src/main/java/io/netty/handler/codec/spdy/SpdyHttpDecoder.java @@ -16,8 +16,8 @@ package io.netty.handler.codec.spdy; import io.netty.buffer.ByteBuf; -import io.netty.buffer.MessageBuf; import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.MessageList; import io.netty.handler.codec.MessageToMessageDecoder; import io.netty.handler.codec.TooLongFrameException; import io.netty.handler.codec.http.DefaultFullHttpRequest; @@ -91,7 +91,7 @@ public class SpdyHttpDecoder extends MessageToMessageDecoder out) + protected void decode(ChannelHandlerContext ctx, SpdyDataOrControlFrame msg, MessageList out) throws Exception { if (msg instanceof SpdySynStreamFrame) { diff --git a/codec-http/src/main/java/io/netty/handler/codec/spdy/SpdyHttpEncoder.java b/codec-http/src/main/java/io/netty/handler/codec/spdy/SpdyHttpEncoder.java index 7400a08227..136f7bb996 100644 --- a/codec-http/src/main/java/io/netty/handler/codec/spdy/SpdyHttpEncoder.java +++ b/codec-http/src/main/java/io/netty/handler/codec/spdy/SpdyHttpEncoder.java @@ -15,8 +15,8 @@ */ package io.netty.handler.codec.spdy; -import io.netty.buffer.MessageBuf; import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.MessageList; import io.netty.handler.codec.MessageToMessageEncoder; import io.netty.handler.codec.UnsupportedMessageTypeException; import io.netty.handler.codec.http.FullHttpRequest; @@ -139,7 +139,7 @@ public class SpdyHttpEncoder extends MessageToMessageEncoder { } @Override - protected void encode(ChannelHandlerContext ctx, HttpObject msg, MessageBuf out) throws Exception { + protected void encode(ChannelHandlerContext ctx, HttpObject msg, MessageList out) throws Exception { boolean valid = false; diff --git a/codec-http/src/main/java/io/netty/handler/codec/spdy/SpdyHttpResponseStreamIdHandler.java b/codec-http/src/main/java/io/netty/handler/codec/spdy/SpdyHttpResponseStreamIdHandler.java index cb18684d67..b30d848465 100644 --- a/codec-http/src/main/java/io/netty/handler/codec/spdy/SpdyHttpResponseStreamIdHandler.java +++ b/codec-http/src/main/java/io/netty/handler/codec/spdy/SpdyHttpResponseStreamIdHandler.java @@ -15,9 +15,9 @@ */ package io.netty.handler.codec.spdy; -import io.netty.buffer.BufUtil; -import io.netty.buffer.MessageBuf; +import io.netty.buffer.ByteBufUtil; import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.MessageList; import io.netty.handler.codec.MessageToMessageCodec; import io.netty.handler.codec.http.HttpMessage; @@ -40,17 +40,17 @@ public class SpdyHttpResponseStreamIdHandler extends } @Override - protected void encode(ChannelHandlerContext ctx, HttpMessage msg, MessageBuf out) throws Exception { + protected void encode(ChannelHandlerContext ctx, HttpMessage msg, MessageList out) throws Exception { Integer id = ids.poll(); if (id != null && id.intValue() != NO_ID && !msg.headers().contains(SpdyHttpHeaders.Names.STREAM_ID)) { SpdyHttpHeaders.setStreamId(msg, id); } - out.add(BufUtil.retain(msg)); + out.add(ByteBufUtil.retain(msg)); } @Override - protected void decode(ChannelHandlerContext ctx, Object msg, MessageBuf out) throws Exception { + protected void decode(ChannelHandlerContext ctx, Object msg, MessageList out) throws Exception { if (msg instanceof HttpMessage) { boolean contains = ((HttpMessage) msg).headers().contains(SpdyHttpHeaders.Names.STREAM_ID); if (!contains) { @@ -62,6 +62,6 @@ public class SpdyHttpResponseStreamIdHandler extends ids.remove(((SpdyRstStreamFrame) msg).getStreamId()); } - out.add(BufUtil.retain(msg)); + out.add(ByteBufUtil.retain(msg)); } } diff --git a/codec-http/src/main/java/io/netty/handler/codec/spdy/SpdyOrHttpChooser.java b/codec-http/src/main/java/io/netty/handler/codec/spdy/SpdyOrHttpChooser.java index 9baca054eb..b14fec68ff 100644 --- a/codec-http/src/main/java/io/netty/handler/codec/spdy/SpdyOrHttpChooser.java +++ b/codec-http/src/main/java/io/netty/handler/codec/spdy/SpdyOrHttpChooser.java @@ -15,14 +15,12 @@ */ package io.netty.handler.codec.spdy; -import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandler; import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.ChannelHandlerUtil; -import io.netty.channel.ChannelInboundByteHandler; -import io.netty.channel.ChannelInboundByteHandlerAdapter; -import io.netty.channel.ChannelInboundMessageHandler; +import io.netty.channel.ChannelInboundHandler; +import io.netty.channel.ChannelInboundHandlerAdapter; import io.netty.channel.ChannelPipeline; +import io.netty.channel.MessageList; import io.netty.handler.codec.http.HttpObjectAggregator; import io.netty.handler.codec.http.HttpRequestDecoder; import io.netty.handler.codec.http.HttpResponseEncoder; @@ -31,11 +29,11 @@ import io.netty.handler.ssl.SslHandler; import javax.net.ssl.SSLEngine; /** - * {@link ChannelInboundByteHandler} which is responsible to setup the {@link ChannelPipeline} either for + * {@link ChannelInboundHandler} which is responsible to setup the {@link ChannelPipeline} either for * HTTP or SPDY. This offers an easy way for users to support both at the same time while not care to * much about the low-level details. */ -public abstract class SpdyOrHttpChooser extends ChannelInboundByteHandlerAdapter { +public abstract class SpdyOrHttpChooser extends ChannelInboundHandlerAdapter { // TODO: Replace with generic NPN handler @@ -63,25 +61,13 @@ public abstract class SpdyOrHttpChooser extends ChannelInboundByteHandlerAdapter protected abstract SelectedProtocol getProtocol(SSLEngine engine); @Override - public ByteBuf newInboundBuffer(ChannelHandlerContext ctx) throws Exception { - return ChannelHandlerUtil.allocate(ctx); - } - - @Override - public void discardInboundReadBytes(ChannelHandlerContext ctx) throws Exception { - // No need to discard anything because this handler will be replaced with something else very quickly. - } - - @Override - public void inboundBufferUpdated(ChannelHandlerContext ctx, ByteBuf in) throws Exception { + public void messageReceived(ChannelHandlerContext ctx, MessageList in) throws Exception { if (initPipeline(ctx)) { - ctx.nextInboundByteBuffer().writeBytes(in); - // When we reached here we can remove this handler as its now clear what protocol we want to use // from this point on. ctx.pipeline().remove(this); - ctx.fireInboundBufferUpdated(); + ctx.fireMessageReceived(in); } } @@ -140,21 +126,21 @@ public abstract class SpdyOrHttpChooser extends ChannelInboundByteHandlerAdapter } /** - * Create the {@link ChannelInboundMessageHandler} that is responsible for handling the http requests + * Create the {@link ChannelInboundHandler} that is responsible for handling the http requests * when the {@link SelectedProtocol} was {@link SelectedProtocol#HTTP_1_0} or * {@link SelectedProtocol#HTTP_1_1} */ - protected abstract ChannelInboundMessageHandler createHttpRequestHandlerForHttp(); + protected abstract ChannelInboundHandler createHttpRequestHandlerForHttp(); /** - * Create the {@link ChannelInboundMessageHandler} that is responsible for handling the http responses + * Create the {@link ChannelInboundHandler} that is responsible for handling the http responses * when the {@link SelectedProtocol} was {@link SelectedProtocol#SPDY_2} or * {@link SelectedProtocol#SPDY_3}. * * Bye default this getMethod will just delecate to {@link #createHttpRequestHandlerForHttp()}, but * sub-classes may override this to change the behaviour. */ - protected ChannelInboundMessageHandler createHttpRequestHandlerForSpdy() { + protected ChannelInboundHandler createHttpRequestHandlerForSpdy() { return createHttpRequestHandlerForHttp(); } } diff --git a/codec-http/src/main/java/io/netty/handler/codec/spdy/SpdySessionHandler.java b/codec-http/src/main/java/io/netty/handler/codec/spdy/SpdySessionHandler.java index 696a1d88b9..fce1fb7b80 100644 --- a/codec-http/src/main/java/io/netty/handler/codec/spdy/SpdySessionHandler.java +++ b/codec-http/src/main/java/io/netty/handler/codec/spdy/SpdySessionHandler.java @@ -15,15 +15,12 @@ */ package io.netty.handler.codec.spdy; -import io.netty.buffer.MessageBuf; -import io.netty.buffer.Unpooled; import io.netty.channel.ChannelDuplexHandler; import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelFutureListener; import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.ChannelInboundMessageHandler; -import io.netty.channel.ChannelOutboundMessageHandler; import io.netty.channel.ChannelPromise; +import io.netty.channel.MessageList; import io.netty.util.internal.EmptyArrays; import java.util.concurrent.atomic.AtomicInteger; @@ -32,8 +29,7 @@ import java.util.concurrent.atomic.AtomicInteger; * Manages streams within a SPDY session. */ public class SpdySessionHandler - extends ChannelDuplexHandler - implements ChannelInboundMessageHandler, ChannelOutboundMessageHandler { + extends ChannelDuplexHandler { private static final SpdyProtocolException PROTOCOL_EXCEPTION = new SpdyProtocolException(); private static final SpdyProtocolException STREAM_CLOSED = new SpdyProtocolException("Stream closed"); @@ -85,21 +81,11 @@ public class SpdySessionHandler } @Override - public MessageBuf newInboundBuffer(ChannelHandlerContext ctx) throws Exception { - return Unpooled.messageBuffer(); - } - - @Override - public MessageBuf newOutboundBuffer(ChannelHandlerContext ctx) throws Exception { - return Unpooled.messageBuffer(); - } - - @Override - public void inboundBufferUpdated(ChannelHandlerContext ctx) throws Exception { - MessageBuf in = ctx.inboundMessageBuffer(); + public void messageReceived(ChannelHandlerContext ctx, MessageList in) throws Exception { boolean handled = false; - for (;;) { - Object msg = in.poll(); + MessageList out = MessageList.newInstance(); + for (int i = 0 ; i < in.size(); i++) { + Object msg = in.get(i); if (msg == null) { break; } @@ -108,18 +94,20 @@ public class SpdySessionHandler // Let the next handlers handle the buffered messages before SYN_STREAM message updates the // lastGoodStreamId. if (handled) { - ctx.fireInboundBufferUpdated(); + ctx.fireMessageReceived(out); + out = MessageList.newInstance(); } } - handleInboundMessage(ctx, msg); + handleInboundMessage(ctx, msg, out); handled = true; } - ctx.fireInboundBufferUpdated(); + in.recycle(); + ctx.fireMessageReceived(out); } - private void handleInboundMessage(ChannelHandlerContext ctx, Object msg) throws Exception { + private void handleInboundMessage(ChannelHandlerContext ctx, Object msg, MessageList out) throws Exception { if (msg instanceof SpdyDataFrame) { @@ -152,22 +140,22 @@ public class SpdySessionHandler // Check if we received a data frame for a Stream-ID which is not open if (!spdySession.isActiveStream(streamID)) { if (streamID <= lastGoodStreamId) { - issueStreamError(ctx, streamID, SpdyStreamStatus.PROTOCOL_ERROR); + issueStreamError(ctx, streamID, SpdyStreamStatus.PROTOCOL_ERROR, out); } else if (!sentGoAwayFrame) { - issueStreamError(ctx, streamID, SpdyStreamStatus.INVALID_STREAM); + issueStreamError(ctx, streamID, SpdyStreamStatus.INVALID_STREAM, out); } return; } // Check if we received a data frame for a stream which is half-closed if (spdySession.isRemoteSideClosed(streamID)) { - issueStreamError(ctx, streamID, SpdyStreamStatus.STREAM_ALREADY_CLOSED); + issueStreamError(ctx, streamID, SpdyStreamStatus.STREAM_ALREADY_CLOSED, out); return; } // Check if we received a data frame before receiving a SYN_REPLY if (!isRemoteInitiatedID(streamID) && !spdySession.hasReceivedReply(streamID)) { - issueStreamError(ctx, streamID, SpdyStreamStatus.PROTOCOL_ERROR); + issueStreamError(ctx, streamID, SpdyStreamStatus.PROTOCOL_ERROR, out); return; } @@ -188,7 +176,7 @@ public class SpdySessionHandler // This difference is stored for the session when writing the SETTINGS frame // and is cleared once we send a WINDOW_UPDATE frame. if (newWindowSize < spdySession.getReceiveWindowSizeLowerBound(streamID)) { - issueStreamError(ctx, streamID, SpdyStreamStatus.FLOW_CONTROL_ERROR); + issueStreamError(ctx, streamID, SpdyStreamStatus.FLOW_CONTROL_ERROR, out); return; } @@ -198,8 +186,7 @@ public class SpdySessionHandler while (spdyDataFrame.content().readableBytes() > initialReceiveWindowSize) { SpdyDataFrame partialDataFrame = new DefaultSpdyDataFrame(streamID, spdyDataFrame.content().readSlice(initialReceiveWindowSize).retain()); - ctx.nextOutboundMessageBuffer().add(partialDataFrame); - ctx.flush(); + ctx.write(partialDataFrame); } } @@ -241,7 +228,7 @@ public class SpdySessionHandler if (spdySynStreamFrame.isInvalid() || !isRemoteInitiatedID(streamID) || spdySession.isActiveStream(streamID)) { - issueStreamError(ctx, streamID, SpdyStreamStatus.PROTOCOL_ERROR); + issueStreamError(ctx, streamID, SpdyStreamStatus.PROTOCOL_ERROR, out); return; } @@ -256,7 +243,7 @@ public class SpdySessionHandler boolean remoteSideClosed = spdySynStreamFrame.isLast(); boolean localSideClosed = spdySynStreamFrame.isUnidirectional(); if (!acceptStream(streamID, priority, remoteSideClosed, localSideClosed)) { - issueStreamError(ctx, streamID, SpdyStreamStatus.REFUSED_STREAM); + issueStreamError(ctx, streamID, SpdyStreamStatus.REFUSED_STREAM, out); return; } @@ -276,13 +263,13 @@ public class SpdySessionHandler if (spdySynReplyFrame.isInvalid() || isRemoteInitiatedID(streamID) || spdySession.isRemoteSideClosed(streamID)) { - issueStreamError(ctx, streamID, SpdyStreamStatus.INVALID_STREAM); + issueStreamError(ctx, streamID, SpdyStreamStatus.INVALID_STREAM, out); return; } // Check if we have received multiple frames for the same Stream-ID if (spdySession.hasReceivedReply(streamID)) { - issueStreamError(ctx, streamID, SpdyStreamStatus.STREAM_IN_USE); + issueStreamError(ctx, streamID, SpdyStreamStatus.STREAM_IN_USE, out); return; } @@ -368,12 +355,12 @@ public class SpdySessionHandler // Check if we received a valid HEADERS frame if (spdyHeadersFrame.isInvalid()) { - issueStreamError(ctx, streamID, SpdyStreamStatus.PROTOCOL_ERROR); + issueStreamError(ctx, streamID, SpdyStreamStatus.PROTOCOL_ERROR, out); return; } if (spdySession.isRemoteSideClosed(streamID)) { - issueStreamError(ctx, streamID, SpdyStreamStatus.INVALID_STREAM); + issueStreamError(ctx, streamID, SpdyStreamStatus.INVALID_STREAM, out); return; } @@ -406,15 +393,15 @@ public class SpdySessionHandler // Check for numerical overflow if (spdySession.getSendWindowSize(streamID) > Integer.MAX_VALUE - deltaWindowSize) { - issueStreamError(ctx, streamID, SpdyStreamStatus.FLOW_CONTROL_ERROR); + issueStreamError(ctx, streamID, SpdyStreamStatus.FLOW_CONTROL_ERROR, out); return; } - updateSendWindowSize(ctx, streamID, deltaWindowSize); + updateSendWindowSize(streamID, deltaWindowSize, out); } } - ctx.nextInboundMessageBuffer().add(msg); + out.add(msg); } @Override @@ -432,10 +419,10 @@ public class SpdySessionHandler } @Override - public void flush(ChannelHandlerContext ctx, ChannelPromise promise) throws Exception { - MessageBuf in = ctx.outboundMessageBuffer(); - for (;;) { - Object msg = in.poll(); + public void write(ChannelHandlerContext ctx, MessageList msgs, ChannelPromise promise) throws Exception { + MessageList out = MessageList.newInstance(); + for (int i = 0; i < msgs.size(); i++) { + Object msg = msgs.get(i); if (msg == null) { break; } @@ -449,24 +436,26 @@ public class SpdySessionHandler msg instanceof SpdyHeadersFrame || msg instanceof SpdyWindowUpdateFrame) { try { - handleOutboundMessage(ctx, msg); + handleOutboundMessage(ctx, msg, out); } catch (SpdyProtocolException e) { if (e == PROTOCOL_EXCEPTION) { - // on the case of PROTOCOL_EXCEPTION faile the promise directly + // on the case of PROTOCOL_EXCEPTION, fail the promise directly // See #1211 promise.setFailure(PROTOCOL_EXCEPTION); return; } } } else { - ctx.nextOutboundMessageBuffer().add(msg); + out.add(msg); } } - ctx.flush(promise); + + msgs.recycle(); + ctx.write(out, promise); } - private void handleOutboundMessage(ChannelHandlerContext ctx, Object msg) throws Exception { - + private void handleOutboundMessage(ChannelHandlerContext ctx, Object msg, MessageList out) + throws Exception { if (msg instanceof SpdyDataFrame) { SpdyDataFrame spdyDataFrame = (SpdyDataFrame) msg; @@ -656,7 +645,7 @@ public class SpdySessionHandler throw PROTOCOL_EXCEPTION; } - ctx.nextOutboundMessageBuffer().add(msg); + out.add(msg); } /* @@ -671,8 +660,7 @@ public class SpdySessionHandler private void issueSessionError( ChannelHandlerContext ctx, SpdySessionStatus status) { - sendGoAwayFrame(ctx, status); - ctx.flush().addListener(ChannelFutureListener.CLOSE); + sendGoAwayFrame(ctx, status).addListener(ChannelFutureListener.CLOSE); } /* @@ -687,7 +675,7 @@ public class SpdySessionHandler * Note: this is only called by the worker thread */ private void issueStreamError( - ChannelHandlerContext ctx, int streamID, SpdyStreamStatus status) { + ChannelHandlerContext ctx, int streamID, SpdyStreamStatus status, MessageList in) { boolean fireMessageReceived = !spdySession.isRemoteSideClosed(streamID); removeStream(ctx, streamID); @@ -695,8 +683,11 @@ public class SpdySessionHandler SpdyRstStreamFrame spdyRstStreamFrame = new DefaultSpdyRstStreamFrame(streamID, status); ctx.write(spdyRstStreamFrame); if (fireMessageReceived) { - ctx.nextInboundMessageBuffer().add(spdyRstStreamFrame); - ctx.fireInboundBufferUpdated(); + in.add(spdyRstStreamFrame); + ctx.fireMessageReceived(in); + while (!in.isEmpty()) { + in.remove(0); + } } } @@ -793,7 +784,7 @@ public class SpdySessionHandler } } - private void updateSendWindowSize(ChannelHandlerContext ctx, final int streamID, int deltaWindowSize) { + private void updateSendWindowSize(final int streamID, int deltaWindowSize, MessageList out) { synchronized (flowControlLock) { int newWindowSize = spdySession.updateSendWindowSize(streamID, deltaWindowSize); @@ -832,7 +823,7 @@ public class SpdySessionHandler halfCloseStream(streamID, false); } - ctx.nextOutboundMessageBuffer().add(spdyDataFrame); + out.add(spdyDataFrame); } else { // We can send a partial frame spdySession.updateSendWindowSize(streamID, -1 * newWindowSize); @@ -858,7 +849,7 @@ public class SpdySessionHandler // } //}); - ctx.nextOutboundMessageBuffer().add(partialDataFrame); + out.add(partialDataFrame); newWindowSize = 0; } @@ -873,8 +864,7 @@ public class SpdySessionHandler return; } - sendGoAwayFrame(ctx, SpdySessionStatus.OK); - ChannelFuture f = ctx.flush(); + ChannelFuture f = sendGoAwayFrame(ctx, SpdySessionStatus.OK); if (spdySession.noActiveStreams()) { f.addListener(new ClosingChannelFutureListener(ctx, future)); } else { @@ -884,12 +874,14 @@ public class SpdySessionHandler // FIXME: Close the connection forcibly after timeout. } - private synchronized void sendGoAwayFrame( + private synchronized ChannelFuture sendGoAwayFrame( ChannelHandlerContext ctx, SpdySessionStatus status) { if (!sentGoAwayFrame) { sentGoAwayFrame = true; SpdyGoAwayFrame spdyGoAwayFrame = new DefaultSpdyGoAwayFrame(lastGoodStreamId, status); - ctx.nextOutboundMessageBuffer().add(spdyGoAwayFrame); + return ctx.write(spdyGoAwayFrame); + } else { + return ctx.newSucceededFuture(); } } diff --git a/codec-http/src/test/java/io/netty/handler/codec/http/HttpClientCodecTest.java b/codec-http/src/test/java/io/netty/handler/codec/http/HttpClientCodecTest.java index 5ba19f180b..07af776a60 100644 --- a/codec-http/src/test/java/io/netty/handler/codec/http/HttpClientCodecTest.java +++ b/codec-http/src/test/java/io/netty/handler/codec/http/HttpClientCodecTest.java @@ -16,7 +16,7 @@ package io.netty.handler.codec.http; import io.netty.buffer.Unpooled; -import io.netty.channel.embedded.EmbeddedByteChannel; +import io.netty.channel.embedded.EmbeddedChannel; import io.netty.handler.codec.CodecException; import io.netty.handler.codec.PrematureChannelClosureException; import io.netty.util.CharsetUtil; @@ -37,7 +37,7 @@ public class HttpClientCodecTest { @Test public void testFailsNotOnRequestResponse() { HttpClientCodec codec = new HttpClientCodec(4096, 8192, 8192, true); - EmbeddedByteChannel ch = new EmbeddedByteChannel(codec); + EmbeddedChannel ch = new EmbeddedChannel(codec); ch.writeOutbound(new DefaultFullHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET, "http://localhost/")); ch.writeInbound(Unpooled.copiedBuffer(RESPONSE, CharsetUtil.ISO_8859_1)); @@ -47,7 +47,7 @@ public class HttpClientCodecTest { @Test public void testFailsNotOnRequestResponseChunked() { HttpClientCodec codec = new HttpClientCodec(4096, 8192, 8192, true); - EmbeddedByteChannel ch = new EmbeddedByteChannel(codec); + EmbeddedChannel ch = new EmbeddedChannel(codec); ch.writeOutbound(new DefaultFullHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET, "http://localhost/")); ch.writeInbound(Unpooled.copiedBuffer(CHUNKED_RESPONSE, CharsetUtil.ISO_8859_1)); @@ -57,7 +57,7 @@ public class HttpClientCodecTest { @Test public void testFailsOnMissingResponse() { HttpClientCodec codec = new HttpClientCodec(4096, 8192, 8192, true); - EmbeddedByteChannel ch = new EmbeddedByteChannel(codec); + EmbeddedChannel ch = new EmbeddedChannel(codec); assertTrue(ch.writeOutbound(new DefaultFullHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET, "http://localhost/"))); @@ -74,7 +74,7 @@ public class HttpClientCodecTest { @Test public void testFailsOnIncompleteChunkedResponse() { HttpClientCodec codec = new HttpClientCodec(4096, 8192, 8192, true); - EmbeddedByteChannel ch = new EmbeddedByteChannel(codec); + EmbeddedChannel ch = new EmbeddedChannel(codec); ch.writeOutbound(new DefaultFullHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET, "http://localhost/")); ch.writeInbound(Unpooled.copiedBuffer(INCOMPLETE_CHUNKED_RESPONSE, CharsetUtil.ISO_8859_1)); diff --git a/codec-http/src/test/java/io/netty/handler/codec/http/HttpContentCompressorTest.java b/codec-http/src/test/java/io/netty/handler/codec/http/HttpContentCompressorTest.java index b0875f9494..113b22cb52 100644 --- a/codec-http/src/test/java/io/netty/handler/codec/http/HttpContentCompressorTest.java +++ b/codec-http/src/test/java/io/netty/handler/codec/http/HttpContentCompressorTest.java @@ -15,7 +15,7 @@ */ package io.netty.handler.codec.http; -import io.netty.channel.embedded.EmbeddedMessageChannel; +import io.netty.channel.embedded.EmbeddedChannel; import io.netty.handler.codec.compression.ZlibWrapper; import io.netty.handler.codec.http.HttpHeaders.Names; import org.junit.Test; @@ -63,7 +63,7 @@ public class HttpContentCompressorTest { @Test public void testEmptyContentCompression() throws Exception { - EmbeddedMessageChannel ch = new EmbeddedMessageChannel(new HttpContentCompressor()); + EmbeddedChannel ch = new EmbeddedChannel(new HttpContentCompressor()); FullHttpRequest req = new DefaultFullHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET, "/"); req.headers().set(Names.ACCEPT_ENCODING, "deflate"); ch.writeInbound(req); diff --git a/codec-http/src/test/java/io/netty/handler/codec/http/HttpContentEncoderTest.java b/codec-http/src/test/java/io/netty/handler/codec/http/HttpContentEncoderTest.java index 8e293cb412..dbf450bf25 100644 --- a/codec-http/src/test/java/io/netty/handler/codec/http/HttpContentEncoderTest.java +++ b/codec-http/src/test/java/io/netty/handler/codec/http/HttpContentEncoderTest.java @@ -19,9 +19,8 @@ package io.netty.handler.codec.http; import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.embedded.EmbeddedByteChannel; -import io.netty.channel.embedded.EmbeddedMessageChannel; -import io.netty.handler.codec.ByteToByteEncoder; +import io.netty.channel.embedded.EmbeddedChannel; +import io.netty.handler.codec.MessageToByteEncoder; import io.netty.handler.codec.http.HttpHeaders.Names; import io.netty.handler.codec.http.HttpHeaders.Values; import io.netty.util.CharsetUtil; @@ -35,9 +34,9 @@ public class HttpContentEncoderTest { private static final class TestEncoder extends HttpContentEncoder { @Override protected Result beginEncode(HttpResponse headers, String acceptEncoding) { - return new Result("test", new EmbeddedByteChannel(new ByteToByteEncoder() { + return new Result("test", new EmbeddedChannel(new MessageToByteEncoder() { @Override - protected void encode(ChannelHandlerContext ctx, ByteBuf in, ByteBuf out) { + protected void encode(ChannelHandlerContext ctx, ByteBuf in, ByteBuf out) throws Exception { out.writeBytes(String.valueOf(in.readableBytes()).getBytes(CharsetUtil.US_ASCII)); in.skipBytes(in.readableBytes()); } @@ -47,7 +46,7 @@ public class HttpContentEncoderTest { @Test public void testSplitContent() throws Exception { - EmbeddedMessageChannel ch = new EmbeddedMessageChannel(new TestEncoder()); + EmbeddedChannel ch = new EmbeddedChannel(new TestEncoder()); ch.writeInbound(new DefaultFullHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET, "/")); ch.writeOutbound(new DefaultHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK)); @@ -71,7 +70,7 @@ public class HttpContentEncoderTest { @Test public void testChunkedContent() throws Exception { - EmbeddedMessageChannel ch = new EmbeddedMessageChannel(new TestEncoder()); + EmbeddedChannel ch = new EmbeddedChannel(new TestEncoder()); ch.writeInbound(new DefaultFullHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET, "/")); HttpResponse res = new DefaultHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK); @@ -98,7 +97,7 @@ public class HttpContentEncoderTest { @Test public void testFullContent() throws Exception { - EmbeddedMessageChannel ch = new EmbeddedMessageChannel(new TestEncoder()); + EmbeddedChannel ch = new EmbeddedChannel(new TestEncoder()); ch.writeInbound(new DefaultFullHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET, "/")); FullHttpResponse res = new DefaultFullHttpResponse( @@ -116,12 +115,12 @@ public class HttpContentEncoderTest { } /** - * If the length of the content is unknown, {@link HttpContentEncoder} should not skip encoding even if the - * actual length is turned out to be 0. + * If the length of the content is unknown, {@link HttpContentEncoder} should not skip encoding the content + * even if the actual length is turned out to be 0. */ @Test public void testEmptySplitContent() throws Exception { - EmbeddedMessageChannel ch = new EmbeddedMessageChannel(new TestEncoder()); + EmbeddedChannel ch = new EmbeddedChannel(new TestEncoder()); ch.writeInbound(new DefaultFullHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET, "/")); ch.writeOutbound(new DefaultHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK)); @@ -129,7 +128,7 @@ public class HttpContentEncoderTest { ch.writeOutbound(LastHttpContent.EMPTY_LAST_CONTENT); HttpContent chunk = (HttpContent) ch.readOutbound(); - assertThat(chunk.content().isReadable(), is(false)); + assertThat(chunk.content().toString(CharsetUtil.US_ASCII), is("0")); assertThat(chunk, is(instanceOf(LastHttpContent.class))); assertThat(ch.readOutbound(), is(nullValue())); } @@ -139,7 +138,7 @@ public class HttpContentEncoderTest { */ @Test public void testEmptyFullContent() throws Exception { - EmbeddedMessageChannel ch = new EmbeddedMessageChannel(new TestEncoder()); + EmbeddedChannel ch = new EmbeddedChannel(new TestEncoder()); ch.writeInbound(new DefaultFullHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET, "/")); FullHttpResponse res = new DefaultFullHttpResponse( @@ -162,7 +161,7 @@ public class HttpContentEncoderTest { assertThat(ch.readOutbound(), is(nullValue())); } - private static void assertEncodedResponse(EmbeddedMessageChannel ch) { + private static void assertEncodedResponse(EmbeddedChannel ch) { Object o = ch.readOutbound(); assertThat(o, is(instanceOf(HttpResponse.class))); diff --git a/codec-http/src/test/java/io/netty/handler/codec/http/HttpInvalidMessageTest.java b/codec-http/src/test/java/io/netty/handler/codec/http/HttpInvalidMessageTest.java index bae6eeea8a..caa5f50fe7 100644 --- a/codec-http/src/test/java/io/netty/handler/codec/http/HttpInvalidMessageTest.java +++ b/codec-http/src/test/java/io/netty/handler/codec/http/HttpInvalidMessageTest.java @@ -17,7 +17,7 @@ package io.netty.handler.codec.http; import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; -import io.netty.channel.embedded.EmbeddedByteChannel; +import io.netty.channel.embedded.EmbeddedChannel; import io.netty.handler.codec.DecoderResult; import io.netty.util.CharsetUtil; import org.junit.Test; @@ -32,7 +32,7 @@ public class HttpInvalidMessageTest { @Test public void testRequestWithBadInitialLine() throws Exception { - EmbeddedByteChannel ch = new EmbeddedByteChannel(new HttpRequestDecoder()); + EmbeddedChannel ch = new EmbeddedChannel(new HttpRequestDecoder()); ch.writeInbound(Unpooled.copiedBuffer("GET / HTTP/1.0 with extra\r\n", CharsetUtil.UTF_8)); HttpRequest req = (HttpRequest) ch.readInbound(); DecoderResult dr = req.getDecoderResult(); @@ -43,7 +43,7 @@ public class HttpInvalidMessageTest { @Test public void testRequestWithBadHeader() throws Exception { - EmbeddedByteChannel ch = new EmbeddedByteChannel(new HttpRequestDecoder()); + EmbeddedChannel ch = new EmbeddedChannel(new HttpRequestDecoder()); ch.writeInbound(Unpooled.copiedBuffer("GET /maybe-something HTTP/1.0\r\n", CharsetUtil.UTF_8)); ch.writeInbound(Unpooled.copiedBuffer("Good_Name: Good Value\r\n", CharsetUtil.UTF_8)); ch.writeInbound(Unpooled.copiedBuffer("Bad=Name: Bad Value\r\n", CharsetUtil.UTF_8)); @@ -59,7 +59,7 @@ public class HttpInvalidMessageTest { @Test public void testResponseWithBadInitialLine() throws Exception { - EmbeddedByteChannel ch = new EmbeddedByteChannel(new HttpResponseDecoder()); + EmbeddedChannel ch = new EmbeddedChannel(new HttpResponseDecoder()); ch.writeInbound(Unpooled.copiedBuffer("HTTP/1.0 BAD_CODE Bad Server\r\n", CharsetUtil.UTF_8)); HttpResponse res = (HttpResponse) ch.readInbound(); DecoderResult dr = res.getDecoderResult(); @@ -70,7 +70,7 @@ public class HttpInvalidMessageTest { @Test public void testResponseWithBadHeader() throws Exception { - EmbeddedByteChannel ch = new EmbeddedByteChannel(new HttpResponseDecoder()); + EmbeddedChannel ch = new EmbeddedChannel(new HttpResponseDecoder()); ch.writeInbound(Unpooled.copiedBuffer("HTTP/1.0 200 Maybe OK\r\n", CharsetUtil.UTF_8)); ch.writeInbound(Unpooled.copiedBuffer("Good_Name: Good Value\r\n", CharsetUtil.UTF_8)); ch.writeInbound(Unpooled.copiedBuffer("Bad=Name: Bad Value\r\n", CharsetUtil.UTF_8)); @@ -86,7 +86,7 @@ public class HttpInvalidMessageTest { @Test public void testBadChunk() throws Exception { - EmbeddedByteChannel ch = new EmbeddedByteChannel(new HttpRequestDecoder()); + EmbeddedChannel ch = new EmbeddedChannel(new HttpRequestDecoder()); ch.writeInbound(Unpooled.copiedBuffer("GET / HTTP/1.0\r\n", CharsetUtil.UTF_8)); ch.writeInbound(Unpooled.copiedBuffer("Transfer-Encoding: chunked\r\n\r\n", CharsetUtil.UTF_8)); ch.writeInbound(Unpooled.copiedBuffer("BAD_LENGTH\r\n", CharsetUtil.UTF_8)); @@ -101,7 +101,7 @@ public class HttpInvalidMessageTest { ensureInboundTrafficDiscarded(ch); } - private void ensureInboundTrafficDiscarded(EmbeddedByteChannel ch) { + private void ensureInboundTrafficDiscarded(EmbeddedChannel ch) { // Generate a lot of random traffic to ensure that it's discarded silently. byte[] data = new byte[1048576]; rnd.nextBytes(data); @@ -109,9 +109,10 @@ public class HttpInvalidMessageTest { ByteBuf buf = Unpooled.wrappedBuffer(data); for (int i = 0; i < 4096; i ++) { buf.setIndex(0, data.length); - ch.writeInbound(buf); + ch.writeInbound(buf.retain()); ch.checkException(); assertNull(ch.readInbound()); } + buf.release(); } } diff --git a/codec-http/src/test/java/io/netty/handler/codec/http/HttpObjectAggregatorTest.java b/codec-http/src/test/java/io/netty/handler/codec/http/HttpObjectAggregatorTest.java index e724bc4513..d6f8fb4676 100644 --- a/codec-http/src/test/java/io/netty/handler/codec/http/HttpObjectAggregatorTest.java +++ b/codec-http/src/test/java/io/netty/handler/codec/http/HttpObjectAggregatorTest.java @@ -19,7 +19,7 @@ import io.netty.buffer.ByteBuf; import io.netty.buffer.CompositeByteBuf; import io.netty.buffer.Unpooled; import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.embedded.EmbeddedMessageChannel; +import io.netty.channel.embedded.EmbeddedChannel; import io.netty.handler.codec.TooLongFrameException; import io.netty.util.CharsetUtil; import org.easymock.EasyMock; @@ -34,7 +34,7 @@ public class HttpObjectAggregatorTest { @Test public void testAggregate() { HttpObjectAggregator aggr = new HttpObjectAggregator(1024 * 1024); - EmbeddedMessageChannel embedder = new EmbeddedMessageChannel(aggr); + EmbeddedChannel embedder = new EmbeddedChannel(aggr); HttpRequest message = new DefaultHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET, "http://localhost"); @@ -73,7 +73,7 @@ public class HttpObjectAggregatorTest { @Test public void testAggregateWithTrailer() { HttpObjectAggregator aggr = new HttpObjectAggregator(1024 * 1024); - EmbeddedMessageChannel embedder = new EmbeddedMessageChannel(aggr); + EmbeddedChannel embedder = new EmbeddedChannel(aggr); HttpRequest message = new DefaultHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET, "http://localhost"); HttpHeaders.setHeader(message, "X-Test", true); @@ -105,7 +105,7 @@ public class HttpObjectAggregatorTest { @Test public void testTooLongFrameException() { HttpObjectAggregator aggr = new HttpObjectAggregator(4); - EmbeddedMessageChannel embedder = new EmbeddedMessageChannel(aggr); + EmbeddedChannel embedder = new EmbeddedChannel(aggr); HttpRequest message = new DefaultHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET, "http://localhost"); HttpContent chunk1 = new DefaultHttpContent(Unpooled.copiedBuffer("test", CharsetUtil.US_ASCII)); @@ -159,7 +159,7 @@ public class HttpObjectAggregatorTest { @Test public void testAggregateTransferEncodingChunked() { HttpObjectAggregator aggr = new HttpObjectAggregator(1024 * 1024); - EmbeddedMessageChannel embedder = new EmbeddedMessageChannel(aggr); + EmbeddedChannel embedder = new EmbeddedChannel(aggr); HttpRequest message = new DefaultHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET, "http://localhost"); diff --git a/codec-http/src/test/java/io/netty/handler/codec/http/HttpServerCodecTest.java b/codec-http/src/test/java/io/netty/handler/codec/http/HttpServerCodecTest.java index 237b30fa56..68771595fc 100644 --- a/codec-http/src/test/java/io/netty/handler/codec/http/HttpServerCodecTest.java +++ b/codec-http/src/test/java/io/netty/handler/codec/http/HttpServerCodecTest.java @@ -17,7 +17,7 @@ package io.netty.handler.codec.http; import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; -import io.netty.channel.embedded.EmbeddedByteChannel; +import io.netty.channel.embedded.EmbeddedChannel; import io.netty.util.CharsetUtil; import org.junit.Assert; import org.junit.Test; @@ -32,10 +32,11 @@ public class HttpServerCodecTest { int maxChunkSize = 2000; HttpServerCodec httpServerCodec = new HttpServerCodec(1000, 1000, maxChunkSize); - EmbeddedByteChannel decoderEmbedder = new EmbeddedByteChannel(httpServerCodec); + EmbeddedChannel decoderEmbedder = new EmbeddedChannel(httpServerCodec); int totalContentLength = maxChunkSize * 5; - decoderEmbedder.writeInbound(Unpooled.copiedBuffer("PUT /test HTTP/1.1\r\n" + + decoderEmbedder.writeInbound(Unpooled.copiedBuffer( + "PUT /test HTTP/1.1\r\n" + "Content-Length: " + totalContentLength + "\r\n" + "\r\n", CharsetUtil.UTF_8)); diff --git a/codec-http/src/test/java/io/netty/handler/codec/http/websocketx/WebSocketFrameAggregatorTest.java b/codec-http/src/test/java/io/netty/handler/codec/http/websocketx/WebSocketFrameAggregatorTest.java index a78ca4c102..f360329a60 100644 --- a/codec-http/src/test/java/io/netty/handler/codec/http/websocketx/WebSocketFrameAggregatorTest.java +++ b/codec-http/src/test/java/io/netty/handler/codec/http/websocketx/WebSocketFrameAggregatorTest.java @@ -17,7 +17,7 @@ package io.netty.handler.codec.http.websocketx; import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; -import io.netty.channel.embedded.EmbeddedMessageChannel; +import io.netty.channel.embedded.EmbeddedChannel; import io.netty.handler.codec.TooLongFrameException; import io.netty.util.CharsetUtil; import org.junit.Assert; @@ -32,7 +32,7 @@ public class WebSocketFrameAggregatorTest { .writeBytes(content2.duplicate()).writeBytes(content3.duplicate()); @Test public void testAggregationBinary() { - EmbeddedMessageChannel channel = new EmbeddedMessageChannel(new WebSocketFrameAggregator(Integer.MAX_VALUE)); + EmbeddedChannel channel = new EmbeddedChannel(new WebSocketFrameAggregator(Integer.MAX_VALUE)); channel.writeInbound(new BinaryWebSocketFrame(true, 1, content1.copy())); channel.writeInbound(new BinaryWebSocketFrame(false, 0, content1.copy())); channel.writeInbound(new ContinuationWebSocketFrame(false, 0, content2.copy())); @@ -42,7 +42,7 @@ public class WebSocketFrameAggregatorTest { Assert.assertTrue(channel.finish()); - System.out.println(channel.lastInboundMessageBuffer().size()); + System.out.println(channel.lastInboundBuffer().size()); BinaryWebSocketFrame frame = (BinaryWebSocketFrame) channel.readInbound(); Assert.assertTrue(frame.isFinalFragment()); Assert.assertEquals(1, frame.rsv()); @@ -68,7 +68,7 @@ public class WebSocketFrameAggregatorTest { @Test public void testAggregationText() { - EmbeddedMessageChannel channel = new EmbeddedMessageChannel(new WebSocketFrameAggregator(Integer.MAX_VALUE)); + EmbeddedChannel channel = new EmbeddedChannel(new WebSocketFrameAggregator(Integer.MAX_VALUE)); channel.writeInbound(new TextWebSocketFrame(true, 1, content1.copy())); channel.writeInbound(new TextWebSocketFrame(false, 0, content1.copy())); channel.writeInbound(new ContinuationWebSocketFrame(false, 0, content2.copy())); @@ -103,7 +103,7 @@ public class WebSocketFrameAggregatorTest { @Test public void textFrameTooBig() { - EmbeddedMessageChannel channel = new EmbeddedMessageChannel(new WebSocketFrameAggregator(8)); + EmbeddedChannel channel = new EmbeddedChannel(new WebSocketFrameAggregator(8)); channel.writeInbound(new BinaryWebSocketFrame(true, 1, content1.copy())); channel.writeInbound(new BinaryWebSocketFrame(false, 0, content1.copy())); try { diff --git a/codec-http/src/test/java/io/netty/handler/codec/http/websocketx/WebSocketServerHandshaker00Test.java b/codec-http/src/test/java/io/netty/handler/codec/http/websocketx/WebSocketServerHandshaker00Test.java index 78354b607f..aa91646b92 100644 --- a/codec-http/src/test/java/io/netty/handler/codec/http/websocketx/WebSocketServerHandshaker00Test.java +++ b/codec-http/src/test/java/io/netty/handler/codec/http/websocketx/WebSocketServerHandshaker00Test.java @@ -17,7 +17,7 @@ package io.netty.handler.codec.http.websocketx; import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; -import io.netty.channel.embedded.EmbeddedByteChannel; +import io.netty.channel.embedded.EmbeddedChannel; import io.netty.handler.codec.http.DefaultFullHttpRequest; import io.netty.handler.codec.http.FullHttpRequest; import io.netty.handler.codec.http.HttpHeaders.Names; @@ -39,7 +39,7 @@ public class WebSocketServerHandshaker00Test { @Test public void testPerformOpeningHandshake() { - EmbeddedByteChannel ch = new EmbeddedByteChannel( + EmbeddedChannel ch = new EmbeddedChannel( new HttpObjectAggregator(42), new HttpRequestDecoder(), new HttpResponseEncoder()); FullHttpRequest req = new DefaultFullHttpRequest( @@ -56,9 +56,9 @@ public class WebSocketServerHandshaker00Test { new WebSocketServerHandshaker00( "ws://example.com/chat", "chat", Integer.MAX_VALUE).handshake(ch, req); - ByteBuf resBuf = ch.readOutbound(); + ByteBuf resBuf = (ByteBuf) ch.readOutbound(); - EmbeddedByteChannel ch2 = new EmbeddedByteChannel(new HttpResponseDecoder()); + EmbeddedChannel ch2 = new EmbeddedChannel(new HttpResponseDecoder()); ch2.writeInbound(resBuf); HttpResponse res = (HttpResponse) ch2.readInbound(); diff --git a/codec-http/src/test/java/io/netty/handler/codec/http/websocketx/WebSocketServerHandshaker08Test.java b/codec-http/src/test/java/io/netty/handler/codec/http/websocketx/WebSocketServerHandshaker08Test.java index f49ac6b101..6b6d3c7aca 100644 --- a/codec-http/src/test/java/io/netty/handler/codec/http/websocketx/WebSocketServerHandshaker08Test.java +++ b/codec-http/src/test/java/io/netty/handler/codec/http/websocketx/WebSocketServerHandshaker08Test.java @@ -16,7 +16,7 @@ package io.netty.handler.codec.http.websocketx; import io.netty.buffer.ByteBuf; -import io.netty.channel.embedded.EmbeddedByteChannel; +import io.netty.channel.embedded.EmbeddedChannel; import io.netty.handler.codec.http.DefaultFullHttpRequest; import io.netty.handler.codec.http.FullHttpRequest; import io.netty.handler.codec.http.HttpHeaders.Names; @@ -36,7 +36,7 @@ public class WebSocketServerHandshaker08Test { @Test public void testPerformOpeningHandshake() { - EmbeddedByteChannel ch = new EmbeddedByteChannel( + EmbeddedChannel ch = new EmbeddedChannel( new HttpObjectAggregator(42), new HttpRequestDecoder(), new HttpResponseEncoder()); FullHttpRequest req = new DefaultFullHttpRequest(HTTP_1_1, HttpMethod.GET, "/chat"); @@ -51,9 +51,9 @@ public class WebSocketServerHandshaker08Test { new WebSocketServerHandshaker08( "ws://example.com/chat", "chat", false, Integer.MAX_VALUE).handshake(ch, req); - ByteBuf resBuf = ch.readOutbound(); + ByteBuf resBuf = (ByteBuf) ch.readOutbound(); - EmbeddedByteChannel ch2 = new EmbeddedByteChannel(new HttpResponseDecoder()); + EmbeddedChannel ch2 = new EmbeddedChannel(new HttpResponseDecoder()); ch2.writeInbound(resBuf); HttpResponse res = (HttpResponse) ch2.readInbound(); diff --git a/codec-http/src/test/java/io/netty/handler/codec/http/websocketx/WebSocketServerHandshaker13Test.java b/codec-http/src/test/java/io/netty/handler/codec/http/websocketx/WebSocketServerHandshaker13Test.java index 791de6a604..aacc460a26 100644 --- a/codec-http/src/test/java/io/netty/handler/codec/http/websocketx/WebSocketServerHandshaker13Test.java +++ b/codec-http/src/test/java/io/netty/handler/codec/http/websocketx/WebSocketServerHandshaker13Test.java @@ -16,7 +16,7 @@ package io.netty.handler.codec.http.websocketx; import io.netty.buffer.ByteBuf; -import io.netty.channel.embedded.EmbeddedByteChannel; +import io.netty.channel.embedded.EmbeddedChannel; import io.netty.handler.codec.http.DefaultFullHttpRequest; import io.netty.handler.codec.http.FullHttpRequest; import io.netty.handler.codec.http.HttpHeaders.Names; @@ -36,7 +36,7 @@ public class WebSocketServerHandshaker13Test { @Test public void testPerformOpeningHandshake() { - EmbeddedByteChannel ch = new EmbeddedByteChannel( + EmbeddedChannel ch = new EmbeddedChannel( new HttpObjectAggregator(42), new HttpRequestDecoder(), new HttpResponseEncoder()); FullHttpRequest req = new DefaultFullHttpRequest(HTTP_1_1, HttpMethod.GET, "/chat"); @@ -51,9 +51,9 @@ public class WebSocketServerHandshaker13Test { new WebSocketServerHandshaker13( "ws://example.com/chat", "chat", false, Integer.MAX_VALUE).handshake(ch, req); - ByteBuf resBuf = ch.readOutbound(); + ByteBuf resBuf = (ByteBuf) ch.readOutbound(); - EmbeddedByteChannel ch2 = new EmbeddedByteChannel(new HttpResponseDecoder()); + EmbeddedChannel ch2 = new EmbeddedChannel(new HttpResponseDecoder()); ch2.writeInbound(resBuf); HttpResponse res = (HttpResponse) ch2.readInbound(); diff --git a/codec-http/src/test/java/io/netty/handler/codec/http/websocketx/WebSocketServerProtocolHandlerTest.java b/codec-http/src/test/java/io/netty/handler/codec/http/websocketx/WebSocketServerProtocolHandlerTest.java index 643363fd16..67f635122b 100644 --- a/codec-http/src/test/java/io/netty/handler/codec/http/websocketx/WebSocketServerProtocolHandlerTest.java +++ b/codec-http/src/test/java/io/netty/handler/codec/http/websocketx/WebSocketServerProtocolHandlerTest.java @@ -15,25 +15,26 @@ */ package io.netty.handler.codec.http.websocketx; -import io.netty.buffer.MessageBuf; -import io.netty.buffer.Unpooled; import io.netty.channel.ChannelHandler; import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.ChannelInboundMessageHandlerAdapter; -import io.netty.channel.ChannelOperationHandlerAdapter; -import io.netty.channel.ChannelOutboundMessageHandler; +import io.netty.channel.ChannelInboundHandlerAdapter; +import io.netty.channel.ChannelOutboundHandlerAdapter; import io.netty.channel.ChannelPromise; -import io.netty.channel.embedded.EmbeddedMessageChannel; +import io.netty.channel.MessageList; +import io.netty.channel.embedded.EmbeddedChannel; import io.netty.handler.codec.http.DefaultFullHttpRequest; import io.netty.handler.codec.http.FullHttpRequest; import io.netty.handler.codec.http.FullHttpResponse; import io.netty.handler.codec.http.HttpMethod; import io.netty.handler.codec.http.HttpRequest; import io.netty.handler.codec.http.HttpRequestDecoder; -import io.netty.handler.codec.http.HttpResponse; import io.netty.handler.codec.http.HttpResponseEncoder; +import org.junit.Before; import org.junit.Test; +import java.util.ArrayDeque; +import java.util.Queue; + import static io.netty.handler.codec.http.HttpHeaders.Values.*; import static io.netty.handler.codec.http.HttpResponseStatus.*; import static io.netty.handler.codec.http.HttpVersion.*; @@ -41,29 +42,36 @@ import static org.junit.Assert.*; public class WebSocketServerProtocolHandlerTest { + private final Queue responses = new ArrayDeque(); + + @Before + public void setUp() { + responses.clear(); + } + @Test public void testHttpUpgradeRequest() throws Exception { - EmbeddedMessageChannel ch = createChannel(new MockOutboundHandler()); + EmbeddedChannel ch = createChannel(new MockOutboundHandler()); ChannelHandlerContext handshakerCtx = ch.pipeline().context(WebSocketServerProtocolHandshakeHandler.class); writeUpgradeRequest(ch); - assertEquals(SWITCHING_PROTOCOLS, ((HttpResponse) ch.outboundMessageBuffer().poll()).getStatus()); + assertEquals(SWITCHING_PROTOCOLS, responses.remove().getStatus()); assertNotNull(WebSocketServerProtocolHandler.getHandshaker(handshakerCtx)); } @Test public void testSubsequentHttpRequestsAfterUpgradeShouldReturn403() throws Exception { - EmbeddedMessageChannel ch = createChannel(new MockOutboundHandler()); + EmbeddedChannel ch = createChannel(); writeUpgradeRequest(ch); - assertEquals(SWITCHING_PROTOCOLS, ((HttpResponse) ch.outboundMessageBuffer().poll()).getStatus()); + assertEquals(SWITCHING_PROTOCOLS, responses.remove().getStatus()); ch.writeInbound(new DefaultFullHttpRequest(HTTP_1_1, HttpMethod.GET, "/test")); - assertEquals(FORBIDDEN, ((HttpResponse) ch.outboundMessageBuffer().poll()).getStatus()); + assertEquals(FORBIDDEN, responses.remove().getStatus()); } @Test public void testHttpUpgradeRequestInvalidUpgradeHeader() { - EmbeddedMessageChannel ch = createChannel(); + EmbeddedChannel ch = createChannel(); FullHttpRequest httpRequestWithEntity = new WebSocketRequestBuilder().httpVersion(HTTP_1_1) .method(HttpMethod.GET) .uri("/test") @@ -74,14 +82,14 @@ public class WebSocketServerProtocolHandlerTest { ch.writeInbound(httpRequestWithEntity); - FullHttpResponse response = getHttpResponse(ch); + FullHttpResponse response = responses.remove(); assertEquals(BAD_REQUEST, response.getStatus()); assertEquals("not a WebSocket handshake request: missing upgrade", getResponseMessage(response)); } @Test public void testHttpUpgradeRequestMissingWSKeyHeader() { - EmbeddedMessageChannel ch = createChannel(); + EmbeddedChannel ch = createChannel(); HttpRequest httpRequest = new WebSocketRequestBuilder().httpVersion(HTTP_1_1) .method(HttpMethod.GET) .uri("/test") @@ -93,7 +101,7 @@ public class WebSocketServerProtocolHandlerTest { ch.writeInbound(httpRequest); - FullHttpResponse response = getHttpResponse(ch); + FullHttpResponse response = responses.remove(); assertEquals(BAD_REQUEST, response.getStatus()); assertEquals("not a WebSocket request: missing key", getResponseMessage(response)); } @@ -101,22 +109,26 @@ public class WebSocketServerProtocolHandlerTest { @Test public void testHandleTextFrame() { CustomTextFrameHandler customTextFrameHandler = new CustomTextFrameHandler(); - EmbeddedMessageChannel ch = createChannel(customTextFrameHandler); + EmbeddedChannel ch = createChannel(customTextFrameHandler); writeUpgradeRequest(ch); - // Removing the HttpRequestDecoder as we are writing a TextWebSocketFrame so decoding is not neccessary. - ch.pipeline().remove(HttpRequestDecoder.class); + + if (ch.pipeline().context(HttpRequestDecoder.class) != null) { + // Removing the HttpRequestDecoder because we are writing a TextWebSocketFrame and thus + // decoding is not neccessary. + ch.pipeline().remove(HttpRequestDecoder.class); + } ch.writeInbound(new TextWebSocketFrame("payload")); assertEquals("processed: payload", customTextFrameHandler.getContent()); } - private static EmbeddedMessageChannel createChannel() { + private EmbeddedChannel createChannel() { return createChannel(null); } - private static EmbeddedMessageChannel createChannel(ChannelHandler handler) { - return new EmbeddedMessageChannel( + private EmbeddedChannel createChannel(ChannelHandler handler) { + return new EmbeddedChannel( new WebSocketServerProtocolHandler("/test", null, false), new HttpRequestDecoder(), new HttpResponseEncoder(), @@ -124,7 +136,7 @@ public class WebSocketServerProtocolHandlerTest { handler); } - private static void writeUpgradeRequest(EmbeddedMessageChannel ch) { + private static void writeUpgradeRequest(EmbeddedChannel ch) { ch.writeInbound(WebSocketRequestBuilder.sucessful()); } @@ -132,31 +144,25 @@ public class WebSocketServerProtocolHandlerTest { return new String(response.content().array()); } - private static FullHttpResponse getHttpResponse(EmbeddedMessageChannel ch) { - MessageBuf outbound = ch.pipeline().context(MockOutboundHandler.class).outboundMessageBuffer(); - return (FullHttpResponse) outbound.poll(); - } - - private static class MockOutboundHandler - extends ChannelOperationHandlerAdapter implements ChannelOutboundMessageHandler { + private class MockOutboundHandler extends ChannelOutboundHandlerAdapter { @Override - public MessageBuf newOutboundBuffer(ChannelHandlerContext ctx) throws Exception { - return Unpooled.messageBuffer(); - } - - @Override - public void flush(ChannelHandlerContext ctx, ChannelPromise future) throws Exception { - //NoOp + public void write(ChannelHandlerContext ctx, MessageList msgs, ChannelPromise promise) + throws Exception { + for (int i = 0; i < msgs.size(); i++) { + responses.add((FullHttpResponse) msgs.get(i)); + } + promise.setSuccess(); } } - private static class CustomTextFrameHandler extends ChannelInboundMessageHandlerAdapter { + private static class CustomTextFrameHandler extends ChannelInboundHandlerAdapter { private String content; @Override - public void messageReceived(ChannelHandlerContext ctx, TextWebSocketFrame msg) throws Exception { - content = "processed: " + msg.text(); + public void messageReceived(ChannelHandlerContext ctx, MessageList msgs) throws Exception { + assertEquals(1, msgs.size()); + content = "processed: " + ((TextWebSocketFrame) msgs.get(0)).text(); } String getContent() { diff --git a/codec-http/src/test/java/io/netty/handler/codec/spdy/SpdySessionHandlerTest.java b/codec-http/src/test/java/io/netty/handler/codec/spdy/SpdySessionHandlerTest.java index bd18a2b6a5..7515ceb888 100644 --- a/codec-http/src/test/java/io/netty/handler/codec/spdy/SpdySessionHandlerTest.java +++ b/codec-http/src/test/java/io/netty/handler/codec/spdy/SpdySessionHandlerTest.java @@ -16,8 +16,9 @@ package io.netty.handler.codec.spdy; import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.ChannelInboundMessageHandlerAdapter; -import io.netty.channel.embedded.EmbeddedMessageChannel; +import io.netty.channel.ChannelInboundHandlerAdapter; +import io.netty.channel.MessageList; +import io.netty.channel.embedded.EmbeddedChannel; import io.netty.util.internal.logging.InternalLogger; import io.netty.util.internal.logging.InternalLoggerFactory; import org.junit.Test; @@ -99,7 +100,7 @@ public class SpdySessionHandlerTest { } private static void testSpdySessionHandler(int version, boolean server) { - EmbeddedMessageChannel sessionHandler = new EmbeddedMessageChannel( + EmbeddedChannel sessionHandler = new EmbeddedChannel( new SpdySessionHandler(version, server), new EchoHandler(closeSignal, server)); while (sessionHandler.readOutbound() != null) { @@ -278,7 +279,7 @@ public class SpdySessionHandlerTest { // Echo Handler opens 4 half-closed streams on session connection // and then sets the number of concurrent streams to 3 - private static class EchoHandler extends ChannelInboundMessageHandlerAdapter { + private static class EchoHandler extends ChannelInboundHandlerAdapter { private final int closeSignal; private final boolean server; @@ -309,35 +310,38 @@ public class SpdySessionHandlerTest { } @Override - public void messageReceived(ChannelHandlerContext ctx, Object msg) throws Exception { - if (msg instanceof SpdyDataFrame || - msg instanceof SpdyPingFrame || - msg instanceof SpdyHeadersFrame) { + public void messageReceived(ChannelHandlerContext ctx, MessageList messages) throws Exception { + for (int i = 0; i < messages.size(); i++) { + Object msg = messages.get(i); + if (msg instanceof SpdyDataFrame || + msg instanceof SpdyPingFrame || + msg instanceof SpdyHeadersFrame) { - ctx.write(msg); - return; - } - - if (msg instanceof SpdySynStreamFrame) { - - SpdySynStreamFrame spdySynStreamFrame = (SpdySynStreamFrame) msg; - if (!spdySynStreamFrame.isUnidirectional()) { - int streamID = spdySynStreamFrame.getStreamId(); - SpdySynReplyFrame spdySynReplyFrame = new DefaultSpdySynReplyFrame(streamID); - spdySynReplyFrame.setLast(spdySynStreamFrame.isLast()); - for (Map.Entry entry: spdySynStreamFrame.headers()) { - spdySynReplyFrame.headers().add(entry.getKey(), entry.getValue()); - } - - ctx.write(spdySynReplyFrame); + ctx.write(msg); + return; } - return; - } - if (msg instanceof SpdySettingsFrame) { - SpdySettingsFrame spdySettingsFrame = (SpdySettingsFrame) msg; - if (spdySettingsFrame.isSet(closeSignal)) { - ctx.close(); + if (msg instanceof SpdySynStreamFrame) { + + SpdySynStreamFrame spdySynStreamFrame = (SpdySynStreamFrame) msg; + if (!spdySynStreamFrame.isUnidirectional()) { + int streamID = spdySynStreamFrame.getStreamId(); + SpdySynReplyFrame spdySynReplyFrame = new DefaultSpdySynReplyFrame(streamID); + spdySynReplyFrame.setLast(spdySynStreamFrame.isLast()); + for (Map.Entry entry: spdySynStreamFrame.headers()) { + spdySynReplyFrame.headers().add(entry.getKey(), entry.getValue()); + } + + ctx.write(spdySynReplyFrame); + } + return; + } + + if (msg instanceof SpdySettingsFrame) { + SpdySettingsFrame spdySettingsFrame = (SpdySettingsFrame) msg; + if (spdySettingsFrame.isSet(closeSignal)) { + ctx.close(); + } } } } diff --git a/codec-socks/pom.xml b/codec-socks/pom.xml index 5e5806e6e2..2771f57ac1 100644 --- a/codec-socks/pom.xml +++ b/codec-socks/pom.xml @@ -20,7 +20,7 @@ io.netty netty-parent - 4.0.0.Final-SNAPSHOT + 4.0.0.CR4-SNAPSHOT netty-codec-socks diff --git a/codec-socks/src/main/java/io/netty/handler/codec/socks/SocksAuthRequestDecoder.java b/codec-socks/src/main/java/io/netty/handler/codec/socks/SocksAuthRequestDecoder.java index 53101ed862..d298fd4917 100644 --- a/codec-socks/src/main/java/io/netty/handler/codec/socks/SocksAuthRequestDecoder.java +++ b/codec-socks/src/main/java/io/netty/handler/codec/socks/SocksAuthRequestDecoder.java @@ -16,8 +16,8 @@ package io.netty.handler.codec.socks; import io.netty.buffer.ByteBuf; -import io.netty.buffer.MessageBuf; import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.MessageList; import io.netty.handler.codec.ReplayingDecoder; import io.netty.util.CharsetUtil; @@ -43,7 +43,7 @@ public class SocksAuthRequestDecoder extends ReplayingDecoder out) throws Exception { + protected void decode(ChannelHandlerContext ctx, ByteBuf byteBuf, MessageList out) throws Exception { switch (state()) { case CHECK_PROTOCOL_VERSION: { version = SocksSubnegotiationVersion.fromByte(byteBuf.readByte()); diff --git a/codec-socks/src/main/java/io/netty/handler/codec/socks/SocksAuthResponseDecoder.java b/codec-socks/src/main/java/io/netty/handler/codec/socks/SocksAuthResponseDecoder.java index 7ba8db8d94..01ed2c2979 100644 --- a/codec-socks/src/main/java/io/netty/handler/codec/socks/SocksAuthResponseDecoder.java +++ b/codec-socks/src/main/java/io/netty/handler/codec/socks/SocksAuthResponseDecoder.java @@ -16,8 +16,8 @@ package io.netty.handler.codec.socks; import io.netty.buffer.ByteBuf; -import io.netty.buffer.MessageBuf; import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.MessageList; import io.netty.handler.codec.ReplayingDecoder; /** @@ -40,7 +40,7 @@ public class SocksAuthResponseDecoder extends ReplayingDecoder out) + protected void decode(ChannelHandlerContext channelHandlerContext, ByteBuf byteBuf, MessageList out) throws Exception { switch (state()) { case CHECK_PROTOCOL_VERSION: { diff --git a/codec-socks/src/main/java/io/netty/handler/codec/socks/SocksCmdRequestDecoder.java b/codec-socks/src/main/java/io/netty/handler/codec/socks/SocksCmdRequestDecoder.java index feadc09982..b85df155e9 100644 --- a/codec-socks/src/main/java/io/netty/handler/codec/socks/SocksCmdRequestDecoder.java +++ b/codec-socks/src/main/java/io/netty/handler/codec/socks/SocksCmdRequestDecoder.java @@ -16,8 +16,8 @@ package io.netty.handler.codec.socks; import io.netty.buffer.ByteBuf; -import io.netty.buffer.MessageBuf; import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.MessageList; import io.netty.handler.codec.ReplayingDecoder; import io.netty.util.CharsetUtil; @@ -46,7 +46,7 @@ public class SocksCmdRequestDecoder extends ReplayingDecoder out) throws Exception { + protected void decode(ChannelHandlerContext ctx, ByteBuf byteBuf, MessageList out) throws Exception { switch (state()) { case CHECK_PROTOCOL_VERSION: { version = SocksProtocolVersion.fromByte(byteBuf.readByte()); diff --git a/codec-socks/src/main/java/io/netty/handler/codec/socks/SocksCmdResponseDecoder.java b/codec-socks/src/main/java/io/netty/handler/codec/socks/SocksCmdResponseDecoder.java index 3670a36dcc..203005dd2d 100644 --- a/codec-socks/src/main/java/io/netty/handler/codec/socks/SocksCmdResponseDecoder.java +++ b/codec-socks/src/main/java/io/netty/handler/codec/socks/SocksCmdResponseDecoder.java @@ -16,8 +16,8 @@ package io.netty.handler.codec.socks; import io.netty.buffer.ByteBuf; -import io.netty.buffer.MessageBuf; import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.MessageList; import io.netty.handler.codec.ReplayingDecoder; import io.netty.util.CharsetUtil; @@ -46,7 +46,7 @@ public class SocksCmdResponseDecoder extends ReplayingDecoder out) throws Exception { + protected void decode(ChannelHandlerContext ctx, ByteBuf byteBuf, MessageList out) throws Exception { switch (state()) { case CHECK_PROTOCOL_VERSION: { version = SocksProtocolVersion.fromByte(byteBuf.readByte()); diff --git a/codec-socks/src/main/java/io/netty/handler/codec/socks/SocksInitRequestDecoder.java b/codec-socks/src/main/java/io/netty/handler/codec/socks/SocksInitRequestDecoder.java index 30102c077c..16c0b7221d 100644 --- a/codec-socks/src/main/java/io/netty/handler/codec/socks/SocksInitRequestDecoder.java +++ b/codec-socks/src/main/java/io/netty/handler/codec/socks/SocksInitRequestDecoder.java @@ -16,8 +16,8 @@ package io.netty.handler.codec.socks; import io.netty.buffer.ByteBuf; -import io.netty.buffer.MessageBuf; import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.MessageList; import io.netty.handler.codec.ReplayingDecoder; import java.util.ArrayList; @@ -44,7 +44,7 @@ public class SocksInitRequestDecoder extends ReplayingDecoder out) throws Exception { + protected void decode(ChannelHandlerContext ctx, ByteBuf byteBuf, MessageList out) throws Exception { switch (state()) { case CHECK_PROTOCOL_VERSION: { version = SocksProtocolVersion.fromByte(byteBuf.readByte()); diff --git a/codec-socks/src/main/java/io/netty/handler/codec/socks/SocksInitResponseDecoder.java b/codec-socks/src/main/java/io/netty/handler/codec/socks/SocksInitResponseDecoder.java index 1978269363..e5c07a2a1c 100644 --- a/codec-socks/src/main/java/io/netty/handler/codec/socks/SocksInitResponseDecoder.java +++ b/codec-socks/src/main/java/io/netty/handler/codec/socks/SocksInitResponseDecoder.java @@ -16,8 +16,8 @@ package io.netty.handler.codec.socks; import io.netty.buffer.ByteBuf; -import io.netty.buffer.MessageBuf; import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.MessageList; import io.netty.handler.codec.ReplayingDecoder; /** @@ -41,7 +41,7 @@ public class SocksInitResponseDecoder extends ReplayingDecoder out) throws Exception { + protected void decode(ChannelHandlerContext ctx, ByteBuf byteBuf, MessageList out) throws Exception { switch (state()) { case CHECK_PROTOCOL_VERSION: { version = SocksProtocolVersion.fromByte(byteBuf.readByte()); diff --git a/codec-socks/src/test/java/io/netty/handler/codec/socks/SocksAuthRequestDecoderTest.java b/codec-socks/src/test/java/io/netty/handler/codec/socks/SocksAuthRequestDecoderTest.java index a94bbeec24..ff8692a521 100644 --- a/codec-socks/src/test/java/io/netty/handler/codec/socks/SocksAuthRequestDecoderTest.java +++ b/codec-socks/src/test/java/io/netty/handler/codec/socks/SocksAuthRequestDecoderTest.java @@ -15,7 +15,7 @@ */ package io.netty.handler.codec.socks; -import io.netty.channel.embedded.EmbeddedByteChannel; +import io.netty.channel.embedded.EmbeddedChannel; import org.junit.Test; import static org.junit.Assert.*; @@ -28,7 +28,7 @@ public class SocksAuthRequestDecoderTest { String password = "test"; SocksAuthRequest msg = new SocksAuthRequest(username, password); SocksAuthRequestDecoder decoder = new SocksAuthRequestDecoder(); - EmbeddedByteChannel embedder = new EmbeddedByteChannel(decoder); + EmbeddedChannel embedder = new EmbeddedChannel(decoder); SocksCommonTestUtils.writeMessageIntoEmbedder(embedder, msg); msg = (SocksAuthRequest) embedder.readInbound(); assertEquals(msg.username(), username); diff --git a/codec-socks/src/test/java/io/netty/handler/codec/socks/SocksAuthResponseDecoderTest.java b/codec-socks/src/test/java/io/netty/handler/codec/socks/SocksAuthResponseDecoderTest.java index ad88597a4d..1604f53bb9 100644 --- a/codec-socks/src/test/java/io/netty/handler/codec/socks/SocksAuthResponseDecoderTest.java +++ b/codec-socks/src/test/java/io/netty/handler/codec/socks/SocksAuthResponseDecoderTest.java @@ -15,7 +15,7 @@ */ package io.netty.handler.codec.socks; -import io.netty.channel.embedded.EmbeddedByteChannel; +import io.netty.channel.embedded.EmbeddedChannel; import io.netty.util.internal.logging.InternalLogger; import io.netty.util.internal.logging.InternalLoggerFactory; import org.junit.Test; @@ -29,7 +29,7 @@ public class SocksAuthResponseDecoderTest { logger.debug("Testing SocksAuthResponseDecoder with authStatus: " + authStatus); SocksAuthResponse msg = new SocksAuthResponse(authStatus); SocksAuthResponseDecoder decoder = new SocksAuthResponseDecoder(); - EmbeddedByteChannel embedder = new EmbeddedByteChannel(decoder); + EmbeddedChannel embedder = new EmbeddedChannel(decoder); SocksCommonTestUtils.writeMessageIntoEmbedder(embedder, msg); msg = (SocksAuthResponse) embedder.readInbound(); assertSame(msg.authStatus(), authStatus); diff --git a/codec-socks/src/test/java/io/netty/handler/codec/socks/SocksCmdRequestDecoderTest.java b/codec-socks/src/test/java/io/netty/handler/codec/socks/SocksCmdRequestDecoderTest.java index 32de008844..8ae2a726db 100644 --- a/codec-socks/src/test/java/io/netty/handler/codec/socks/SocksCmdRequestDecoderTest.java +++ b/codec-socks/src/test/java/io/netty/handler/codec/socks/SocksCmdRequestDecoderTest.java @@ -15,7 +15,7 @@ */ package io.netty.handler.codec.socks; -import io.netty.channel.embedded.EmbeddedByteChannel; +import io.netty.channel.embedded.EmbeddedChannel; import io.netty.util.internal.logging.InternalLogger; import io.netty.util.internal.logging.InternalLoggerFactory; import org.junit.Test; @@ -34,7 +34,7 @@ public class SocksCmdRequestDecoderTest { " port: " + port); SocksCmdRequest msg = new SocksCmdRequest(cmdType, addressType, host, port); SocksCmdRequestDecoder decoder = new SocksCmdRequestDecoder(); - EmbeddedByteChannel embedder = new EmbeddedByteChannel(decoder); + EmbeddedChannel embedder = new EmbeddedChannel(decoder); SocksCommonTestUtils.writeMessageIntoEmbedder(embedder, msg); if (msg.addressType() == SocksAddressType.UNKNOWN) { assertTrue(embedder.readInbound() instanceof UnknownSocksRequest); diff --git a/codec-socks/src/test/java/io/netty/handler/codec/socks/SocksCmdResponseDecoderTest.java b/codec-socks/src/test/java/io/netty/handler/codec/socks/SocksCmdResponseDecoderTest.java index f058780d36..9f2691dc96 100644 --- a/codec-socks/src/test/java/io/netty/handler/codec/socks/SocksCmdResponseDecoderTest.java +++ b/codec-socks/src/test/java/io/netty/handler/codec/socks/SocksCmdResponseDecoderTest.java @@ -15,7 +15,7 @@ */ package io.netty.handler.codec.socks; -import io.netty.channel.embedded.EmbeddedByteChannel; +import io.netty.channel.embedded.EmbeddedChannel; import io.netty.util.internal.logging.InternalLogger; import io.netty.util.internal.logging.InternalLoggerFactory; import org.junit.Test; @@ -25,12 +25,12 @@ import static org.junit.Assert.*; public class SocksCmdResponseDecoderTest { private static final InternalLogger logger = InternalLoggerFactory.getInstance(SocksCmdResponseDecoderTest.class); - private static void testSocksCmdResponseDecoderWithDifferentParams(SocksCmdStatus cmdStatus, - SocksAddressType addressType) { + private static void testSocksCmdResponseDecoderWithDifferentParams( + SocksCmdStatus cmdStatus, SocksAddressType addressType) { logger.debug("Testing cmdStatus: " + cmdStatus + " addressType: " + addressType); SocksResponse msg = new SocksCmdResponse(cmdStatus, addressType); SocksCmdResponseDecoder decoder = new SocksCmdResponseDecoder(); - EmbeddedByteChannel embedder = new EmbeddedByteChannel(decoder); + EmbeddedChannel embedder = new EmbeddedChannel(decoder); SocksCommonTestUtils.writeMessageIntoEmbedder(embedder, msg); if (addressType == SocksAddressType.UNKNOWN) { assertTrue(embedder.readInbound() instanceof UnknownSocksResponse); diff --git a/codec-socks/src/test/java/io/netty/handler/codec/socks/SocksCommonTestUtils.java b/codec-socks/src/test/java/io/netty/handler/codec/socks/SocksCommonTestUtils.java index ade7a7e417..f4a54dbad0 100644 --- a/codec-socks/src/test/java/io/netty/handler/codec/socks/SocksCommonTestUtils.java +++ b/codec-socks/src/test/java/io/netty/handler/codec/socks/SocksCommonTestUtils.java @@ -17,7 +17,7 @@ package io.netty.handler.codec.socks; import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; -import io.netty.channel.embedded.EmbeddedByteChannel; +import io.netty.channel.embedded.EmbeddedChannel; final class SocksCommonTestUtils { /** @@ -27,7 +27,7 @@ final class SocksCommonTestUtils { //NOOP } - public static void writeMessageIntoEmbedder(EmbeddedByteChannel embedder, SocksMessage msg) { + public static void writeMessageIntoEmbedder(EmbeddedChannel embedder, SocksMessage msg) { ByteBuf buf = Unpooled.buffer(); msg.encodeAsByteBuf(buf); embedder.writeInbound(buf); diff --git a/codec/pom.xml b/codec/pom.xml index b12012909f..a11717c764 100644 --- a/codec/pom.xml +++ b/codec/pom.xml @@ -20,7 +20,7 @@ io.netty netty-parent - 4.0.0.Final-SNAPSHOT + 4.0.0.CR4-SNAPSHOT netty-codec diff --git a/codec/src/main/java/io/netty/handler/codec/ByteToByteCodec.java b/codec/src/main/java/io/netty/handler/codec/ByteToByteCodec.java deleted file mode 100644 index 2907e6a00a..0000000000 --- a/codec/src/main/java/io/netty/handler/codec/ByteToByteCodec.java +++ /dev/null @@ -1,127 +0,0 @@ -/* - * Copyright 2012 The Netty Project - * - * The Netty Project licenses this file to you under the Apache License, - * version 2.0 (the "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. - */ -package io.netty.handler.codec; - -import io.netty.buffer.ByteBuf; -import io.netty.channel.ChannelDuplexHandler; -import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.ChannelInboundByteHandler; -import io.netty.channel.ChannelOutboundByteHandler; -import io.netty.channel.ChannelPromise; - -/** - * A Codec for on-the-fly encoding/decoding of bytes. - * - * This can be thought of as a combination of {@link ByteToByteDecoder} and {@link ByteToByteEncoder}. - * - * Here is an example of a {@link ByteToByteCodec} which just square {@link Integer} read from a {@link ByteBuf}. - *
- *     public class SquareCodec extends {@link ByteToByteCodec} {
- *         {@code @Override}
- *         public void decode({@link ChannelHandlerContext} ctx, {@link ByteBuf} in, {@link ByteBuf} out)
- *                 throws {@link Exception} {
- *             if (in.readableBytes() < 4) {
- *                 return;
- *             }
- *             int value = in.readInt();
- *             out.writeInt(value * value);
- *         }
- *
- *         {@code @Overrride}
- *         public void encode({@link ChannelHandlerContext} ctx, {@link ByteBuf} in, {@link ByteBuf} out)
- *                 throws {@link Exception} {
- *             if (in.readableBytes() < 4) {
- *                 return;
- *             }
- *             int value = in.readInt();
- *             out.writeInt(value / value);
- *         }
- *     }
- * 
- */ -public abstract class ByteToByteCodec - extends ChannelDuplexHandler - implements ChannelInboundByteHandler, ChannelOutboundByteHandler { - - private final ByteToByteEncoder encoder = new ByteToByteEncoder() { - @Override - protected void encode( - ChannelHandlerContext ctx, - ByteBuf in, ByteBuf out) throws Exception { - ByteToByteCodec.this.encode(ctx, in, out); - } - }; - - private final ByteToByteDecoder decoder = new ByteToByteDecoder() { - @Override - protected void decode(ChannelHandlerContext ctx, ByteBuf in, ByteBuf out) throws Exception { - ByteToByteCodec.this.decode(ctx, in, out); - } - - @Override - protected void decodeLast(ChannelHandlerContext ctx, ByteBuf in, ByteBuf out) throws Exception { - ByteToByteCodec.this.decodeLast(ctx, in, out); - } - }; - - @Override - public ByteBuf newInboundBuffer(ChannelHandlerContext ctx) throws Exception { - return decoder.newInboundBuffer(ctx); - } - - @Override - public void inboundBufferUpdated(ChannelHandlerContext ctx) throws Exception { - decoder.inboundBufferUpdated(ctx); - } - - @Override - public ByteBuf newOutboundBuffer(ChannelHandlerContext ctx) throws Exception { - return encoder.newOutboundBuffer(ctx); - } - - @Override - public void flush( - ChannelHandlerContext ctx, ChannelPromise promise) throws Exception { - encoder.flush(ctx, promise); - } - - @Override - public void discardInboundReadBytes(ChannelHandlerContext ctx) throws Exception { - decoder.discardInboundReadBytes(ctx); - } - - @Override - public void discardOutboundReadBytes(ChannelHandlerContext ctx) throws Exception { - encoder.discardOutboundReadBytes(ctx); - } - - /** - * @see {@link ByteToByteEncoder#encode(ChannelHandlerContext, ByteBuf, ByteBuf)} - */ - protected abstract void encode(ChannelHandlerContext ctx, ByteBuf in, ByteBuf out) throws Exception; - - /** - * @see {@link ByteToByteDecoder#decode(ChannelHandlerContext, ByteBuf, ByteBuf)} - */ - protected abstract void decode(ChannelHandlerContext ctx, ByteBuf in, ByteBuf out) throws Exception; - - /** - * @see {@link ByteToByteDecoder#decodeLast(ChannelHandlerContext, ByteBuf, ByteBuf)} - */ - protected void decodeLast(ChannelHandlerContext ctx, ByteBuf in, ByteBuf out) throws Exception { - decode(ctx, in, out); - } -} diff --git a/codec/src/main/java/io/netty/handler/codec/ByteToByteDecoder.java b/codec/src/main/java/io/netty/handler/codec/ByteToByteDecoder.java deleted file mode 100644 index a2ad13ead7..0000000000 --- a/codec/src/main/java/io/netty/handler/codec/ByteToByteDecoder.java +++ /dev/null @@ -1,142 +0,0 @@ -/* - * Copyright 2012 The Netty Project - * - * The Netty Project licenses this file to you under the Apache License, - * version 2.0 (the "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. - */ -package io.netty.handler.codec; - -import io.netty.buffer.ByteBuf; -import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.ChannelInboundByteHandlerAdapter; - -/** - * {@link ChannelInboundByteHandlerAdapter} which decodes bytes in a stream-like fashion from one {@link ByteBuf} to an - * other. - * - * This kind of decoder is often useful for doing on-the-fly processiing like i.e. compression. - * - * But you can also do other things with it. For example here is an implementation which reads {@link Integer}s from - * the input {@link ByteBuf} and square them before write them to the output {@link ByteBuf}. - * - *
- *     public class SquareDecoder extends {@link ByteToByteDecoder} {
- *         {@code @Override}
- *         public void decode({@link ChannelHandlerContext} ctx, {@link ByteBuf} in, {@link ByteBuf} out)
- *                 throws {@link Exception} {
- *             if (in.readableBytes() < 4) {
- *                 return;
- *             }
- *             int value = in.readInt();
- *             out.writeInt(value * value);
- *         }
- *     }
- * 
- */ -public abstract class ByteToByteDecoder extends ChannelInboundByteHandlerAdapter { - - private volatile boolean singleDecode; - - /** - * If set then only one message is decoded on each {@link #inboundBufferUpdated(ChannelHandlerContext)} call. - * This may be useful if you need to do some protocol upgrade and want to make sure nothing is mixed up. - * - * Default is {@code false} as this has performance impacts. - */ - public void setSingleDecode(boolean singleDecode) { - this.singleDecode = singleDecode; - } - - /** - * If {@code true} then only one message is decoded on each - * {@link #inboundBufferUpdated(ChannelHandlerContext)} call. - * - * Default is {@code false} as this has performance impacts. - */ - public boolean isSingleDecode() { - return singleDecode; - } - - @Override - public void inboundBufferUpdated(ChannelHandlerContext ctx, ByteBuf in) throws Exception { - callDecode(ctx, in, ctx.nextInboundByteBuffer()); - } - - @Override - public void channelInactive(ChannelHandlerContext ctx) throws Exception { - ByteBuf in = ctx.inboundByteBuffer(); - ByteBuf out = ctx.nextInboundByteBuffer(); - if (!in.isReadable()) { - callDecode(ctx, in, out); - } - - int oldOutSize = out.readableBytes(); - try { - decodeLast(ctx, in, out); - } catch (CodecException e) { - throw e; - } catch (Throwable t) { - throw new DecoderException(t); - } finally { - if (out.readableBytes() > oldOutSize) { - ctx.fireInboundBufferUpdated(); - } - ctx.fireChannelInactive(); - } - } - - /** - * Call the {@link #decode(ChannelHandlerContext, ByteBuf, ByteBuf)} method until it is done. - */ - private void callDecode(ChannelHandlerContext ctx, ByteBuf in, ByteBuf out) { - int oldOutSize = out.readableBytes(); - try { - while (in.isReadable()) { - int oldInSize = in.readableBytes(); - decode(ctx, in, out); - if (oldInSize == in.readableBytes() || isSingleDecode()) { - break; - } - } - } catch (CodecException e) { - throw e; - } catch (Throwable t) { - throw new DecoderException(t); - } finally { - if (out.readableBytes() > oldOutSize) { - ctx.fireInboundBufferUpdated(); - } - } - } - - /** - * Decode the from one {@link ByteBuf} to an other. This method will be called till either the input - * {@link ByteBuf} has nothing to read anymore or till nothing was read from the input {@link ByteBuf}. - * - * @param ctx the {@link ChannelHandlerContext} which this {@link ByteToByteDecoder} belongs to - * @param in the {@link ByteBuf} from which to read data - * @param out the {@link ByteBuf} to which the decoded data will be written - * @throws Exception is thrown if an error accour - */ - protected abstract void decode(ChannelHandlerContext ctx, ByteBuf in, ByteBuf out) throws Exception; - - /** - * Is called one last time when the {@link ChannelHandlerContext} goes in-active. Which means the - * {@link #channelInactive(ChannelHandlerContext)} was triggered. - * - * By default this will just call {@link #decode(ChannelHandlerContext, ByteBuf, ByteBuf)} but sub-classes may - * override this for some special cleanup operation. - */ - protected void decodeLast(ChannelHandlerContext ctx, ByteBuf in, ByteBuf out) throws Exception { - decode(ctx, in, out); - } -} diff --git a/codec/src/main/java/io/netty/handler/codec/ByteToByteEncoder.java b/codec/src/main/java/io/netty/handler/codec/ByteToByteEncoder.java deleted file mode 100644 index f1ed0f9212..0000000000 --- a/codec/src/main/java/io/netty/handler/codec/ByteToByteEncoder.java +++ /dev/null @@ -1,150 +0,0 @@ -/* - * Copyright 2012 The Netty Project - * - * The Netty Project licenses this file to you under the Apache License, - * version 2.0 (the "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. - */ -package io.netty.handler.codec; - -import io.netty.buffer.ByteBuf; -import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.ChannelOutboundByteHandlerAdapter; -import io.netty.channel.ChannelPromise; -import io.netty.channel.FileRegion; -import io.netty.channel.IncompleteFlushException; - -import java.io.EOFException; -import java.io.IOException; -import java.nio.ByteBuffer; -import java.nio.channels.WritableByteChannel; - -/** - * {@link ChannelOutboundByteHandlerAdapter} which encodes bytes in a stream-like fashion from one {@link ByteBuf} to an - * other. - * - * This kind of decoder is often useful for doing on-the-fly processing like i.e. compression. - * - * But you can also do other things with it. For example here is an implementation which reads {@link Integer}s from - * the input {@link ByteBuf} and square them before write them to the output {@link ByteBuf}. - * - *
- *     public class SquareEncoder extends {@link ByteToByteEncoder} {
- *         {@code @Override}
- *         public void encode({@link ChannelHandlerContext} ctx, {@link ByteBuf} in, {@link ByteBuf} out)
- *                 throws {@link Exception} {
- *             if (in.readableBytes() < 4) {
- *                 return;
- *             }
- *             int value = in.readInt();
- *             out.writeInt(value * value);
- *         }
- *     }
- * 
- */ -public abstract class ByteToByteEncoder extends ChannelOutboundByteHandlerAdapter { - - @Override - protected void flush(ChannelHandlerContext ctx, ByteBuf in, ChannelPromise promise) throws Exception { - ByteBuf out = ctx.nextOutboundByteBuffer(); - boolean encoded = false; - - try { - while (in.isReadable()) { - int oldInSize = in.readableBytes(); - encode(ctx, in, out); - encoded = true; - if (oldInSize == in.readableBytes()) { - break; - } - } - } catch (Throwable t) { - if (!(t instanceof CodecException)) { - t = new EncoderException(t); - } - if (encoded) { - t = new IncompleteFlushException("unable to encode all bytes", t); - } - in.discardSomeReadBytes(); - promise.setFailure(t); - return; - } - - ctx.flush(promise); - } - - @Override - public void sendFile(ChannelHandlerContext ctx, FileRegion region, ChannelPromise promise) throws Exception { - long written = 0; - try { - for (;;) { - long localWritten = region.transferTo(new BufferChannel(ctx.outboundByteBuffer()), written); - if (localWritten == -1) { - checkEOF(region, written); - flush(ctx, promise); - break; - } - written += localWritten; - if (written >= region.count()) { - flush(ctx, promise); - break; - } - } - } catch (IOException e) { - promise.setFailure(new EncoderException(e)); - } finally { - region.release(); - } - } - - private static void checkEOF(FileRegion region, long writtenBytes) throws IOException { - if (writtenBytes < region.count()) { - throw new EOFException("Expected to be able to write " - + region.count() + " bytes, but only wrote " - + writtenBytes); - } - } - - private static final class BufferChannel implements WritableByteChannel { - private final ByteBuf buffer; - - BufferChannel(ByteBuf buffer) { - this.buffer = buffer; - } - @Override - public int write(ByteBuffer src) { - int bytes = src.remaining(); - buffer.writeBytes(src); - return bytes; - } - - @Override - public boolean isOpen() { - return buffer.refCnt() > 0; - } - - @Override - public void close() { - // NOOP - } - } - - /** - * Encodes the from one {@link ByteBuf} to an other. This method will be called till either the input - * {@link ByteBuf} has nothing to read anymore or till nothing was read from the input {@link ByteBuf}. - * - * @param ctx the {@link ChannelHandlerContext} which this {@link ByteToByteDecoder} belongs to - * @param in the {@link ByteBuf} from which to read data - * @param out the {@link ByteBuf} to which the decoded data will be written - * @throws Exception is thrown if an error accour - */ - protected abstract void encode(ChannelHandlerContext ctx, ByteBuf in, ByteBuf out) throws Exception; -} diff --git a/codec/src/main/java/io/netty/handler/codec/ByteToMessageCodec.java b/codec/src/main/java/io/netty/handler/codec/ByteToMessageCodec.java index b44331b4b6..7622510c35 100644 --- a/codec/src/main/java/io/netty/handler/codec/ByteToMessageCodec.java +++ b/codec/src/main/java/io/netty/handler/codec/ByteToMessageCodec.java @@ -16,16 +16,13 @@ package io.netty.handler.codec; import io.netty.buffer.ByteBuf; -import io.netty.buffer.MessageBuf; import io.netty.channel.ChannelDuplexHandler; import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.ChannelInboundByteHandler; -import io.netty.channel.ChannelOutboundMessageHandler; import io.netty.channel.ChannelPromise; +import io.netty.channel.MessageList; import io.netty.util.internal.TypeParameterMatcher; -public abstract class ByteToMessageCodec extends ChannelDuplexHandler - implements ChannelInboundByteHandler, ChannelOutboundMessageHandler { +public abstract class ByteToMessageCodec extends ChannelDuplexHandler { private final TypeParameterMatcher outboundMsgMatcher; private final MessageToByteEncoder encoder = new MessageToByteEncoder() { @@ -42,12 +39,12 @@ public abstract class ByteToMessageCodec extends ChannelDuplexHandler private final ByteToMessageDecoder decoder = new ByteToMessageDecoder() { @Override - public void decode(ChannelHandlerContext ctx, ByteBuf in, MessageBuf out) throws Exception { + public void decode(ChannelHandlerContext ctx, ByteBuf in, MessageList out) throws Exception { ByteToMessageCodec.this.decode(ctx, in, out); } @Override - protected void decodeLast(ChannelHandlerContext ctx, ByteBuf in, MessageBuf out) throws Exception { + protected void decodeLast(ChannelHandlerContext ctx, ByteBuf in, MessageList out) throws Exception { ByteToMessageCodec.this.decodeLast(ctx, in, out); } }; @@ -60,38 +57,23 @@ public abstract class ByteToMessageCodec extends ChannelDuplexHandler outboundMsgMatcher = TypeParameterMatcher.get(outboundMessageType); } - @Override - public ByteBuf newInboundBuffer(ChannelHandlerContext ctx) throws Exception { - return decoder.newInboundBuffer(ctx); - } - - @Override - public void discardInboundReadBytes(ChannelHandlerContext ctx) throws Exception { - decoder.discardInboundReadBytes(ctx); - } - - @Override - public MessageBuf newOutboundBuffer(ChannelHandlerContext ctx) throws Exception { - return encoder.newOutboundBuffer(ctx); - } - - @Override - public void inboundBufferUpdated(ChannelHandlerContext ctx) throws Exception { - decoder.inboundBufferUpdated(ctx); - } - - @Override - public void flush(ChannelHandlerContext ctx, ChannelPromise promise) throws Exception { - encoder.flush(ctx, promise); - } - public boolean acceptOutboundMessage(Object msg) throws Exception { return outboundMsgMatcher.match(msg); } + @Override + public void messageReceived(ChannelHandlerContext ctx, MessageList msgs) throws Exception { + decoder.messageReceived(ctx, msgs); + } + + @Override + public void write(ChannelHandlerContext ctx, MessageList msgs, ChannelPromise promise) throws Exception { + encoder.write(ctx, msgs, promise); + } + protected abstract void encode(ChannelHandlerContext ctx, I msg, ByteBuf out) throws Exception; - protected abstract void decode(ChannelHandlerContext ctx, ByteBuf in, MessageBuf out) throws Exception; - protected void decodeLast(ChannelHandlerContext ctx, ByteBuf in, MessageBuf out) throws Exception { + protected abstract void decode(ChannelHandlerContext ctx, ByteBuf in, MessageList out) throws Exception; + protected void decodeLast(ChannelHandlerContext ctx, ByteBuf in, MessageList out) throws Exception { decode(ctx, in, out); } } diff --git a/codec/src/main/java/io/netty/handler/codec/ByteToMessageDecoder.java b/codec/src/main/java/io/netty/handler/codec/ByteToMessageDecoder.java index 6366340c63..7ed8d7fdb7 100644 --- a/codec/src/main/java/io/netty/handler/codec/ByteToMessageDecoder.java +++ b/codec/src/main/java/io/netty/handler/codec/ByteToMessageDecoder.java @@ -16,14 +16,15 @@ package io.netty.handler.codec; import io.netty.buffer.ByteBuf; -import io.netty.buffer.MessageBuf; +import io.netty.buffer.Unpooled; import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.ChannelInboundByteHandler; -import io.netty.channel.ChannelInboundByteHandlerAdapter; +import io.netty.channel.ChannelInboundHandlerAdapter; +import io.netty.channel.MessageList; +import io.netty.util.internal.StringUtil; /** - * {@link ChannelInboundByteHandler} which decodes bytes in a stream-like fashion from one {@link ByteBuf} to an other - * Message type. + * {@link ChannelInboundHandlerAdapter} which decodes bytes in a stream-like fashion from one {@link ByteBuf} to an + * other Message type. * * For example here is an implementation which reads all readable bytes from * the input {@link ByteBuf} and create a new {@link ByteBuf}. @@ -31,22 +32,24 @@ import io.netty.channel.ChannelInboundByteHandlerAdapter; *
  *     public class SquareDecoder extends {@link ByteToMessageDecoder} {
  *         {@code @Override}
- *         public void decode({@link ChannelHandlerContext} ctx, {@link ByteBuf} in, {@link MessageBuf} out)
+ *         public void decode({@link ChannelHandlerContext} ctx, {@link ByteBuf} in, {@link MessageList} out)
  *                 throws {@link Exception} {
  *             out.add(in.readBytes(in.readableBytes()));
  *         }
  *     }
  * 
*/ -public abstract class ByteToMessageDecoder - extends ChannelInboundByteHandlerAdapter { +public abstract class ByteToMessageDecoder extends ChannelInboundHandlerAdapter { + protected ByteBuf cumulation; private volatile boolean singleDecode; private boolean decodeWasNull; + private MessageList out; + private boolean removed; /** - * If set then only one message is decoded on each {@link #inboundBufferUpdated(ChannelHandlerContext)} call. - * This may be useful if you need to do some protocol upgrade and want to make sure nothing is mixed up. + * If set then only one message is decoded on each {@link #messageReceived(ChannelHandlerContext, MessageList)} + * call. This may be useful if you need to do some protocol upgrade and want to make sure nothing is mixed up. * * Default is {@code false} as this has performance impacts. */ @@ -56,7 +59,7 @@ public abstract class ByteToMessageDecoder /** * If {@code true} then only one message is decoded on each - * {@link #inboundBufferUpdated(ChannelHandlerContext)} call. + * {@link #messageReceived(ChannelHandlerContext, MessageList)} call. * * Default is {@code false} as this has performance impacts. */ @@ -64,9 +67,119 @@ public abstract class ByteToMessageDecoder return singleDecode; } + /** + * Returns the actual number of readable bytes in the internal cumulative + * buffer of this decoder. You usually do not need to rely on this value + * to write a decoder. Use it only when you must use it at your own risk. + * This method is a shortcut to {@link #internalBuffer() internalBuffer().readableBytes()}. + */ + protected int actualReadableBytes() { + return internalBuffer().readableBytes(); + } + + /** + * Returns the internal cumulative buffer of this decoder. You usually + * do not need to access the internal buffer directly to write a decoder. + * Use it only when you must use it at your own risk. + */ + protected ByteBuf internalBuffer() { + if (cumulation != null) { + return cumulation; + } else { + return Unpooled.EMPTY_BUFFER; + } + } + @Override - public void inboundBufferUpdated(ChannelHandlerContext ctx, ByteBuf in) throws Exception { - callDecode(ctx, in); + public final void handlerRemoved(ChannelHandlerContext ctx) throws Exception { + removed = true; + ByteBuf buf = internalBuffer(); + if (buf.isReadable()) { + if (out == null) { + ctx.fireMessageReceived(buf); + } else { + out.add(buf.copy()); + } + buf.clear(); + } + handlerRemoved0(); + } + + /** + * Gets called after the {@link ByteToMessageDecoder} was removed from the actual context and it doesn't handle + * events anymore. + */ + protected void handlerRemoved0() throws Exception { } + + @Override + public void messageReceived(ChannelHandlerContext ctx, MessageList msgs) throws Exception { + out = MessageList.newInstance(); + try { + int size = msgs.size(); + for (int i = 0; i < size; i ++) { + Object m = msgs.get(i); + // handler was removed in the loop + if (removed) { + out.add(m); + continue; + } + if (m instanceof ByteBuf) { + ByteBuf data = (ByteBuf) m; + if (cumulation == null) { + cumulation = data; + try { + callDecode(ctx, data, out); + } finally { + if (!data.isReadable()) { + cumulation = null; + data.release(); + } + } + } else { + try { + if (cumulation.writerIndex() > cumulation.maxCapacity() - data.readableBytes()) { + ByteBuf oldCumulation = cumulation; + cumulation = ctx.alloc().buffer(oldCumulation.readableBytes() + data.readableBytes()); + cumulation.writeBytes(oldCumulation); + oldCumulation.release(); + } + cumulation.writeBytes(data); + callDecode(ctx, cumulation, out); + } finally { + if (!cumulation.isReadable()) { + cumulation.release(); + cumulation = null; + } else { + cumulation.discardSomeReadBytes(); + } + data.release(); + } + } + } else { + out.add(m); + } + } + } catch (DecoderException e) { + throw e; + } catch (Throwable t) { + throw new DecoderException(t); + } finally { + // release the cumulation if the handler was removed while messages are processed + if (removed) { + if (cumulation != null) { + cumulation.release(); + cumulation = null; + } + removed = false; + } + MessageList out = this.out; + this.out = null; + if (out.isEmpty()) { + decodeWasNull = true; + } + msgs.recycle(); + ctx.fireMessageReceived(out); + } } @Override @@ -82,35 +195,36 @@ public abstract class ByteToMessageDecoder @Override public void channelInactive(ChannelHandlerContext ctx) throws Exception { - OutputMessageBuf out = OutputMessageBuf.get(); + MessageList out = MessageList.newInstance(); try { - ByteBuf in = ctx.inboundByteBuffer(); - if (in.isReadable()) { - callDecode(ctx, in); + if (cumulation != null) { + callDecode(ctx, cumulation, out); + decodeLast(ctx, cumulation, out); + } else { + decodeLast(ctx, Unpooled.EMPTY_BUFFER, out); } - decodeLast(ctx, in, out); - } catch (CodecException e) { + } catch (DecoderException e) { throw e; - } catch (Throwable cause) { - throw new DecoderException(cause); + } catch (Exception e) { + throw new DecoderException(e); } finally { - if (out.drainToNextInbound(ctx)) { - ctx.fireInboundBufferUpdated(); + if (cumulation != null) { + cumulation.release(); + cumulation = null; } + + ctx.fireMessageReceived(out); ctx.fireChannelInactive(); } } - protected void callDecode(ChannelHandlerContext ctx, ByteBuf in) { - boolean wasNull = false; - OutputMessageBuf out = OutputMessageBuf.get(); + protected void callDecode(ChannelHandlerContext ctx, ByteBuf in, MessageList out) { try { while (in.isReadable()) { int outSize = out.size(); int oldInputLength = in.readableBytes(); decode(ctx, in, out); if (outSize == out.size()) { - wasNull = true; if (oldInputLength == in.readableBytes()) { break; } else { @@ -118,10 +232,10 @@ public abstract class ByteToMessageDecoder } } - wasNull = false; if (oldInputLength == in.readableBytes()) { - throw new IllegalStateException( - "decode() did not read anything but decoded a message."); + throw new DecoderException( + StringUtil.simpleClassName(getClass()) + + ".decode() did not read anything but decoded a message."); } if (isSingleDecode()) { @@ -132,15 +246,6 @@ public abstract class ByteToMessageDecoder throw e; } catch (Throwable cause) { throw new DecoderException(cause); - } finally { - if (out.drainToNextInbound(ctx)) { - decodeWasNull = false; - ctx.fireInboundBufferUpdated(); - } else { - if (wasNull) { - decodeWasNull = true; - } - } } } @@ -149,22 +254,22 @@ public abstract class ByteToMessageDecoder * {@link ByteBuf} has nothing to read anymore, till nothing was read from the input {@link ByteBuf} or till * this method returns {@code null}. * - * @param ctx the {@link ChannelHandlerContext} which this {@link ByteToByteDecoder} belongs to + * @param ctx the {@link ChannelHandlerContext} which this {@link ByteToMessageDecoder} belongs to * @param in the {@link ByteBuf} from which to read data - * @param out the {@link MessageBuf} to which decoded messages should be added + * @param out the {@link MessageList} to which decoded messages should be added * @throws Exception is thrown if an error accour */ - protected abstract void decode(ChannelHandlerContext ctx, ByteBuf in, MessageBuf out) throws Exception; + protected abstract void decode(ChannelHandlerContext ctx, ByteBuf in, MessageList out) throws Exception; /** * Is called one last time when the {@link ChannelHandlerContext} goes in-active. Which means the * {@link #channelInactive(ChannelHandlerContext)} was triggered. * - * By default this will just call {@link #decode(ChannelHandlerContext, ByteBuf, MessageBuf)} but sub-classes may + * By default this will just call {@link #decode(ChannelHandlerContext, ByteBuf, MessageList)} but sub-classes may * override this for some special cleanup operation. */ - protected void decodeLast(ChannelHandlerContext ctx, ByteBuf in, MessageBuf out) throws Exception { + protected void decodeLast(ChannelHandlerContext ctx, ByteBuf in, MessageList out) throws Exception { decode(ctx, in, out); } } diff --git a/codec/src/main/java/io/netty/handler/codec/DelimiterBasedFrameDecoder.java b/codec/src/main/java/io/netty/handler/codec/DelimiterBasedFrameDecoder.java index 3d22a7dc83..1a0a02d2fa 100644 --- a/codec/src/main/java/io/netty/handler/codec/DelimiterBasedFrameDecoder.java +++ b/codec/src/main/java/io/netty/handler/codec/DelimiterBasedFrameDecoder.java @@ -16,8 +16,8 @@ package io.netty.handler.codec; import io.netty.buffer.ByteBuf; -import io.netty.buffer.MessageBuf; import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.MessageList; /** * A decoder that splits the received {@link ByteBuf}s by one or more @@ -211,7 +211,7 @@ public class DelimiterBasedFrameDecoder extends ByteToMessageDecoder { } @Override - protected void decode(ChannelHandlerContext ctx, ByteBuf in, MessageBuf out) throws Exception { + protected void decode(ChannelHandlerContext ctx, ByteBuf in, MessageList out) throws Exception { Object decoded = decode(ctx, in); if (decoded != null) { out.add(decoded); diff --git a/codec/src/main/java/io/netty/handler/codec/FixedLengthFrameDecoder.java b/codec/src/main/java/io/netty/handler/codec/FixedLengthFrameDecoder.java index 600c19babd..3cc025e711 100644 --- a/codec/src/main/java/io/netty/handler/codec/FixedLengthFrameDecoder.java +++ b/codec/src/main/java/io/netty/handler/codec/FixedLengthFrameDecoder.java @@ -16,9 +16,8 @@ package io.netty.handler.codec; import io.netty.buffer.ByteBuf; -import io.netty.buffer.MessageBuf; import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.ChannelHandlerUtil; +import io.netty.channel.MessageList; /** * A decoder that splits the received {@link ByteBuf}s by the fixed number @@ -39,51 +38,30 @@ import io.netty.channel.ChannelHandlerUtil; public class FixedLengthFrameDecoder extends ByteToMessageDecoder { private final int frameLength; - private final boolean allocateFullBuffer; - - /** - * Calls {@link #FixedLengthFrameDecoder(int, boolean)} with {@code false} - */ - public FixedLengthFrameDecoder(int frameLength) { - this(frameLength, false); - } /** * Creates a new instance. * - * @param frameLength - * the length of the frame - * @param allocateFullBuffer - * {@code true} if the cumulative {@link ByteBuf} should use the - * {@link #frameLength} as its initial size + * @param frameLength the length of the frame */ - public FixedLengthFrameDecoder(int frameLength, boolean allocateFullBuffer) { + public FixedLengthFrameDecoder(int frameLength) { if (frameLength <= 0) { throw new IllegalArgumentException( "frameLength must be a positive integer: " + frameLength); } this.frameLength = frameLength; - this.allocateFullBuffer = allocateFullBuffer; } @Override - public ByteBuf newInboundBuffer(ChannelHandlerContext ctx) throws Exception { - if (allocateFullBuffer) { - return ChannelHandlerUtil.allocate(ctx, frameLength); - } else { - return super.newInboundBuffer(ctx); - } - } - - @Override - protected void decode(ChannelHandlerContext ctx, ByteBuf in, MessageBuf out) throws Exception { + protected void decode(ChannelHandlerContext ctx, ByteBuf in, MessageList out) throws Exception { Object decoded = decode(ctx, in); if (decoded != null) { out.add(decoded); } } - protected Object decode(ChannelHandlerContext ctx, ByteBuf in) throws Exception { + protected Object decode( + @SuppressWarnings("UnusedParameters") ChannelHandlerContext ctx, ByteBuf in) throws Exception { if (in.readableBytes() < frameLength) { return null; } else { diff --git a/codec/src/main/java/io/netty/handler/codec/LengthFieldBasedFrameDecoder.java b/codec/src/main/java/io/netty/handler/codec/LengthFieldBasedFrameDecoder.java index b9a6e357b2..d554eff759 100644 --- a/codec/src/main/java/io/netty/handler/codec/LengthFieldBasedFrameDecoder.java +++ b/codec/src/main/java/io/netty/handler/codec/LengthFieldBasedFrameDecoder.java @@ -16,9 +16,9 @@ package io.netty.handler.codec; import io.netty.buffer.ByteBuf; -import io.netty.buffer.MessageBuf; import io.netty.buffer.Unpooled; import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.MessageList; import io.netty.handler.codec.serialization.ObjectDecoder; import java.nio.ByteOrder; @@ -348,7 +348,7 @@ public class LengthFieldBasedFrameDecoder extends ByteToMessageDecoder { } @Override - protected void decode(ChannelHandlerContext ctx, ByteBuf in, MessageBuf out) throws Exception { + protected void decode(ChannelHandlerContext ctx, ByteBuf in, MessageList out) throws Exception { Object decoded = decode(ctx, in); if (decoded != null) { out.add(decoded); diff --git a/codec/src/main/java/io/netty/handler/codec/LineBasedFrameDecoder.java b/codec/src/main/java/io/netty/handler/codec/LineBasedFrameDecoder.java index 41153fc25f..414ebb38c0 100644 --- a/codec/src/main/java/io/netty/handler/codec/LineBasedFrameDecoder.java +++ b/codec/src/main/java/io/netty/handler/codec/LineBasedFrameDecoder.java @@ -16,8 +16,8 @@ package io.netty.handler.codec; import io.netty.buffer.ByteBuf; -import io.netty.buffer.MessageBuf; import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.MessageList; /** * A decoder that splits the received {@link ByteBuf}s on line endings. @@ -69,7 +69,7 @@ public class LineBasedFrameDecoder extends ByteToMessageDecoder { } @Override - protected void decode(ChannelHandlerContext ctx, ByteBuf in, MessageBuf out) throws Exception { + protected void decode(ChannelHandlerContext ctx, ByteBuf in, MessageList out) throws Exception { Object decoded = decode(ctx, in); if (decoded != null) { out.add(decoded); diff --git a/codec/src/main/java/io/netty/handler/codec/MessageToByteEncoder.java b/codec/src/main/java/io/netty/handler/codec/MessageToByteEncoder.java index 9aec6d9823..9072105de7 100644 --- a/codec/src/main/java/io/netty/handler/codec/MessageToByteEncoder.java +++ b/codec/src/main/java/io/netty/handler/codec/MessageToByteEncoder.java @@ -16,13 +16,16 @@ package io.netty.handler.codec; import io.netty.buffer.ByteBuf; -import io.netty.buffer.MessageBuf; +import io.netty.buffer.ByteBufUtil; import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.ChannelOutboundMessageHandlerAdapter; +import io.netty.channel.ChannelOutboundHandlerAdapter; +import io.netty.channel.ChannelPromise; +import io.netty.channel.MessageList; +import io.netty.util.internal.TypeParameterMatcher; /** - * {@link ChannelOutboundMessageHandlerAdapter} which encodes message in a stream-like fashion from one message to an + * {@link ChannelOutboundHandlerAdapter} which encodes message in a stream-like fashion from one message to an * {@link ByteBuf}. * * @@ -38,27 +41,73 @@ import io.netty.channel.ChannelOutboundMessageHandlerAdapter; * } * */ -public abstract class MessageToByteEncoder extends ChannelOutboundMessageHandlerAdapter { +public abstract class MessageToByteEncoder extends ChannelOutboundHandlerAdapter { - protected MessageToByteEncoder() { } + private final TypeParameterMatcher matcher; + + protected MessageToByteEncoder() { + matcher = TypeParameterMatcher.find(this, MessageToByteEncoder.class, "I"); + } protected MessageToByteEncoder(Class outboundMessageType) { - super(outboundMessageType); + matcher = TypeParameterMatcher.get(outboundMessageType); + } + + public boolean acceptOutboundMessage(Object msg) throws Exception { + return matcher.match(msg); } @Override - public void flush(ChannelHandlerContext ctx, I msg) throws Exception { + public void write(ChannelHandlerContext ctx, MessageList msgs, ChannelPromise promise) throws Exception { + MessageList out = MessageList.newInstance(); + boolean success = false; try { - encode(ctx, msg, ctx.nextOutboundByteBuffer()); - } catch (CodecException e) { + ByteBuf buf = null; + int size = msgs.size(); + for (int i = 0; i < size; i ++) { + Object m = msgs.get(i); + if (acceptOutboundMessage(m)) { + @SuppressWarnings("unchecked") + I cast = (I) m; + if (buf == null) { + buf = ctx.alloc().buffer(); + } + try { + encode(ctx, cast, buf); + } finally { + ByteBufUtil.release(cast); + } + } else { + if (buf != null && buf.isReadable()) { + out.add(buf); + buf = null; + } + + out.add(m); + } + } + + if (buf != null && buf.isReadable()) { + out.add(buf); + } + + success = true; + } catch (EncoderException e) { throw e; - } catch (Exception e) { - throw new CodecException(e); + } catch (Throwable e) { + throw new EncoderException(e); + } finally { + msgs.recycle(); + if (success) { + ctx.write(out, promise); + } else { + out.releaseAllAndRecycle(); + } } } /** - * Encode a message into a {@link ByteBuf}. This method will be called till the {@link MessageBuf} has + * Encode a message into a {@link ByteBuf}. This method will be called till the {@link MessageList} has * nothing left. * * @param ctx the {@link ChannelHandlerContext} which this {@link MessageToByteEncoder} belongs to diff --git a/codec/src/main/java/io/netty/handler/codec/MessageToMessageCodec.java b/codec/src/main/java/io/netty/handler/codec/MessageToMessageCodec.java index f2bd26a43b..8f22b7b2e7 100644 --- a/codec/src/main/java/io/netty/handler/codec/MessageToMessageCodec.java +++ b/codec/src/main/java/io/netty/handler/codec/MessageToMessageCodec.java @@ -15,12 +15,10 @@ */ package io.netty.handler.codec; -import io.netty.buffer.MessageBuf; import io.netty.channel.ChannelDuplexHandler; import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.ChannelInboundMessageHandler; -import io.netty.channel.ChannelOutboundMessageHandler; import io.netty.channel.ChannelPromise; +import io.netty.channel.MessageList; import io.netty.util.internal.TypeParameterMatcher; /** @@ -48,13 +46,10 @@ import io.netty.util.internal.TypeParameterMatcher; * } * */ -public abstract class MessageToMessageCodec - extends ChannelDuplexHandler - implements ChannelInboundMessageHandler, - ChannelOutboundMessageHandler { +public abstract class MessageToMessageCodec extends ChannelDuplexHandler { + + private final MessageToMessageEncoder encoder = new MessageToMessageEncoder() { - private final MessageToMessageEncoder encoder = - new MessageToMessageEncoder() { @Override public boolean acceptOutboundMessage(Object msg) throws Exception { return MessageToMessageCodec.this.acceptOutboundMessage(msg); @@ -62,13 +57,12 @@ public abstract class MessageToMessageCodec @Override @SuppressWarnings("unchecked") - protected void encode(ChannelHandlerContext ctx, Object msg, MessageBuf out) throws Exception { + protected void encode(ChannelHandlerContext ctx, Object msg, MessageList out) throws Exception { MessageToMessageCodec.this.encode(ctx, (OUTBOUND_IN) msg, out); } }; - private final MessageToMessageDecoder decoder = - new MessageToMessageDecoder() { + private final MessageToMessageDecoder decoder = new MessageToMessageDecoder() { @Override public boolean acceptInboundMessage(Object msg) throws Exception { @@ -77,7 +71,7 @@ public abstract class MessageToMessageCodec @Override @SuppressWarnings("unchecked") - protected void decode(ChannelHandlerContext ctx, Object msg, MessageBuf out) throws Exception { + protected void decode(ChannelHandlerContext ctx, Object msg, MessageList out) throws Exception { MessageToMessageCodec.this.decode(ctx, (INBOUND_IN) msg, out); } }; @@ -97,26 +91,13 @@ public abstract class MessageToMessageCodec } @Override - @SuppressWarnings("unchecked") - public MessageBuf newInboundBuffer(ChannelHandlerContext ctx) throws Exception { - return (MessageBuf) decoder.newInboundBuffer(ctx); + public void messageReceived(ChannelHandlerContext ctx, MessageList msgs) throws Exception { + decoder.messageReceived(ctx, msgs); } @Override - @SuppressWarnings("unchecked") - public MessageBuf newOutboundBuffer(ChannelHandlerContext ctx) throws Exception { - return (MessageBuf) encoder.newOutboundBuffer(ctx); - } - - @Override - public void inboundBufferUpdated( - ChannelHandlerContext ctx) throws Exception { - decoder.inboundBufferUpdated(ctx); - } - - @Override - public void flush(ChannelHandlerContext ctx, ChannelPromise future) throws Exception { - encoder.flush(ctx, future); + public void write(ChannelHandlerContext ctx, MessageList msgs, ChannelPromise promise) throws Exception { + encoder.write(ctx, msgs, promise); } /** @@ -137,6 +118,8 @@ public abstract class MessageToMessageCodec return outboundMsgMatcher.match(msg); } - protected abstract void encode(ChannelHandlerContext ctx, OUTBOUND_IN msg, MessageBuf out) throws Exception; - protected abstract void decode(ChannelHandlerContext ctx, INBOUND_IN msg, MessageBuf out) throws Exception; + protected abstract void encode(ChannelHandlerContext ctx, OUTBOUND_IN msg, MessageList out) + throws Exception; + protected abstract void decode(ChannelHandlerContext ctx, INBOUND_IN msg, MessageList out) + throws Exception; } diff --git a/codec/src/main/java/io/netty/handler/codec/MessageToMessageDecoder.java b/codec/src/main/java/io/netty/handler/codec/MessageToMessageDecoder.java index 91d24eb4da..14b8d8a3ec 100644 --- a/codec/src/main/java/io/netty/handler/codec/MessageToMessageDecoder.java +++ b/codec/src/main/java/io/netty/handler/codec/MessageToMessageDecoder.java @@ -15,13 +15,14 @@ */ package io.netty.handler.codec; -import io.netty.buffer.MessageBuf; +import io.netty.buffer.ByteBufUtil; import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.ChannelInboundMessageHandler; -import io.netty.channel.ChannelInboundMessageHandlerAdapter; +import io.netty.channel.ChannelInboundHandlerAdapter; +import io.netty.channel.MessageList; +import io.netty.util.internal.TypeParameterMatcher; /** - * {@link ChannelInboundMessageHandler} which decodes from one message to an other message + * {@link ChannelInboundHandlerAdapter} which decodes from one message to an other message * * For example here is an implementation which decodes a {@link String} to an {@link Integer} which represent * the length of the {@link String}. @@ -32,43 +33,66 @@ import io.netty.channel.ChannelInboundMessageHandlerAdapter; * * {@code @Override} * public void decode({@link ChannelHandlerContext} ctx, {@link String} message, - * {@link MessageBuf} out) throws {@link Exception} { + * {@link MessageList} out) throws {@link Exception} { * out.add(message.length()); * } * } * * */ -public abstract class MessageToMessageDecoder extends ChannelInboundMessageHandlerAdapter { +public abstract class MessageToMessageDecoder extends ChannelInboundHandlerAdapter { - protected MessageToMessageDecoder() { } + private final TypeParameterMatcher matcher; + + protected MessageToMessageDecoder() { + matcher = TypeParameterMatcher.find(this, MessageToMessageDecoder.class, "I"); + } protected MessageToMessageDecoder(Class inboundMessageType) { - super(inboundMessageType); + matcher = TypeParameterMatcher.get(inboundMessageType); + } + + public boolean acceptInboundMessage(Object msg) throws Exception { + return matcher.match(msg); } @Override - public final void messageReceived(ChannelHandlerContext ctx, I msg) throws Exception { - OutputMessageBuf out = OutputMessageBuf.get(); + public void messageReceived(ChannelHandlerContext ctx, MessageList msgs) throws Exception { + MessageList out = MessageList.newInstance(); try { - decode(ctx, msg, out); - } catch (CodecException e) { + int size = msgs.size(); + for (int i = 0; i < size; i ++) { + Object m = msgs.get(i); + if (acceptInboundMessage(m)) { + @SuppressWarnings("unchecked") + I cast = (I) m; + try { + decode(ctx, cast, out); + } finally { + ByteBufUtil.release(cast); + } + } else { + out.add(m); + } + } + } catch (DecoderException e) { throw e; - } catch (Throwable cause) { - throw new DecoderException(cause); + } catch (Exception e) { + throw new DecoderException(e); } finally { - out.drainToNextInbound(ctx); + msgs.recycle(); + ctx.fireMessageReceived(out); } } /** - * Decode from one message to an other. This method will be called till either the {@link MessageBuf} has + * Decode from one message to an other. This method will be called till either the {@link MessageList} has * nothing left or till this method returns {@code null}. * * @param ctx the {@link ChannelHandlerContext} which this {@link MessageToMessageDecoder} belongs to * @param msg the message to decode to an other one - * @param out the {@link MessageBuf} to which decoded messages should be added + * @param out the {@link MessageList} to which decoded messages should be added * @throws Exception is thrown if an error accour */ - protected abstract void decode(ChannelHandlerContext ctx, I msg, MessageBuf out) throws Exception; + protected abstract void decode(ChannelHandlerContext ctx, I msg, MessageList out) throws Exception; } diff --git a/codec/src/main/java/io/netty/handler/codec/MessageToMessageEncoder.java b/codec/src/main/java/io/netty/handler/codec/MessageToMessageEncoder.java index 4195ba9c3a..f82416d1da 100644 --- a/codec/src/main/java/io/netty/handler/codec/MessageToMessageEncoder.java +++ b/codec/src/main/java/io/netty/handler/codec/MessageToMessageEncoder.java @@ -15,12 +15,15 @@ */ package io.netty.handler.codec; -import io.netty.buffer.MessageBuf; +import io.netty.buffer.ByteBufUtil; import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.ChannelOutboundMessageHandlerAdapter; +import io.netty.channel.ChannelOutboundHandlerAdapter; +import io.netty.channel.ChannelPromise; +import io.netty.channel.MessageList; +import io.netty.util.internal.TypeParameterMatcher; /** - * {@link ChannelOutboundMessageHandlerAdapter} which encodes from one message to an other message + * {@link ChannelOutboundHandlerAdapter} which encodes from one message to an other message * * For example here is an implementation which decodes an {@link Integer} to an {@link String}. * @@ -29,7 +32,7 @@ import io.netty.channel.ChannelOutboundMessageHandlerAdapter; * {@link MessageToMessageEncoder}<{@link Integer}> { * * {@code @Override} - * public void encode({@link ChannelHandlerContext} ctx, {@link Integer} message, {@link MessageBuf} out) + * public void encode({@link ChannelHandlerContext} ctx, {@link Integer} message, {@link MessageList} out) * throws {@link Exception} { * out.add(message.toString()); * } @@ -37,37 +40,66 @@ import io.netty.channel.ChannelOutboundMessageHandlerAdapter; * * */ -public abstract class MessageToMessageEncoder extends ChannelOutboundMessageHandlerAdapter { +public abstract class MessageToMessageEncoder extends ChannelOutboundHandlerAdapter { - protected MessageToMessageEncoder() { } + private final TypeParameterMatcher matcher; + + protected MessageToMessageEncoder() { + matcher = TypeParameterMatcher.find(this, MessageToMessageEncoder.class, "I"); + } protected MessageToMessageEncoder(Class outboundMessageType) { - super(outboundMessageType); + matcher = TypeParameterMatcher.get(outboundMessageType); + } + + public boolean acceptOutboundMessage(Object msg) throws Exception { + return matcher.match(msg); } @Override - public final void flush(ChannelHandlerContext ctx, I msg) throws Exception { - OutputMessageBuf out = OutputMessageBuf.get(); + public void write(ChannelHandlerContext ctx, MessageList msgs, ChannelPromise promise) throws Exception { + MessageList out = MessageList.newInstance(); + boolean success = false; try { - encode(ctx, msg, out); + int size = msgs.size(); + for (int i = 0; i < size; i ++) { + Object m = msgs.get(i); + if (acceptOutboundMessage(m)) { + @SuppressWarnings("unchecked") + I cast = (I) m; + try { + encode(ctx, cast, out); + } finally { + ByteBufUtil.release(cast); + } + } else { + out.add(m); + } + } + success = true; } catch (CodecException e) { throw e; - } catch (Throwable cause) { - throw new EncoderException(cause); + } catch (Throwable t) { + throw new EncoderException(t); } finally { - out.drainToNextOutbound(ctx); + msgs.recycle(); + if (success) { + ctx.write(out, promise); + } else { + out.releaseAllAndRecycle(); + } } } /** - * Encode from one message to an other. This method will be called till either the {@link MessageBuf} has nothing + * Encode from one message to an other. This method will be called till either the {@link MessageList} has nothing * left or till this method returns {@code null}. * * @param ctx the {@link ChannelHandlerContext} which this {@link MessageToMessageEncoder} belongs to * @param msg the message to encode to an other one - * @param out the {@link MessageBuf} into which the encoded msg should be added + * @param out the {@link MessageList} into which the encoded msg should be added * needs to do some kind of aggragation * @throws Exception is thrown if an error accour */ - protected abstract void encode(ChannelHandlerContext ctx, I msg, MessageBuf out) throws Exception; + protected abstract void encode(ChannelHandlerContext ctx, I msg, MessageList out) throws Exception; } diff --git a/codec/src/main/java/io/netty/handler/codec/OutputMessageBuf.java b/codec/src/main/java/io/netty/handler/codec/OutputMessageBuf.java deleted file mode 100644 index 5491853cbd..0000000000 --- a/codec/src/main/java/io/netty/handler/codec/OutputMessageBuf.java +++ /dev/null @@ -1,177 +0,0 @@ -/* - * Copyright 2013 The Netty Project - * - * The Netty Project licenses this file to you under the Apache License, - * version 2.0 (the "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. - */ -package io.netty.handler.codec; - -import io.netty.buffer.BufType; -import io.netty.buffer.BufUtil; -import io.netty.buffer.ByteBuf; -import io.netty.buffer.DefaultMessageBuf; -import io.netty.buffer.MessageBuf; -import io.netty.channel.ChannelHandlerContext; - -final class OutputMessageBuf extends DefaultMessageBuf { - - private static final ThreadLocal output = - new ThreadLocal() { - @Override - protected OutputMessageBuf initialValue() { - return new OutputMessageBuf(); - } - - @Override - public OutputMessageBuf get() { - OutputMessageBuf buf = super.get(); - assert buf.isEmpty(); - return buf; - } - }; - - static OutputMessageBuf get() { - return output.get(); - } - - private int byteBufCnt; - - private OutputMessageBuf() { - super(2); - } - - @Override - public boolean offer(Object e) { - boolean added = super.offer(e); - if (added) { - if (e instanceof ByteBuf) { - byteBufCnt ++; - } - } - return added; - } - - @Override - public boolean remove(Object o) { - boolean removed = super.remove(o); - if (removed) { - if (o instanceof ByteBuf) { - byteBufCnt --; - } - } - return removed; - } - - @Override - public Object poll() { - Object o = super.poll(); - if (o == null) { - return o; - } - if (o instanceof ByteBuf) { - byteBufCnt --; - } - return o; - } - - @Override - public void clear() { - super.clear(); - byteBufCnt = 0; - } - - public boolean drainToNextInbound(ChannelHandlerContext ctx) { - final int size = size(); - if (size == 0) { - return false; - } - - final int byteBufCnt = this.byteBufCnt; - if (byteBufCnt == 0 || ctx.nextInboundBufferType() != BufType.BYTE) { - return drainTo(ctx.nextInboundMessageBuffer()) > 0; - } - - final ByteBuf nextByteBuf = ctx.nextInboundByteBuffer(); - if (byteBufCnt == size) { - // Contains only ByteBufs - for (Object o = poll();;) { - writeAndRelease(nextByteBuf, (ByteBuf) o); - if ((o = poll()) == null) { - break; - } - } - } else { - // Contains both ByteBufs and non-ByteBufs (0 < byteBufCnt < size()) - final MessageBuf nextMsgBuf = ctx.nextInboundMessageBuffer(); - for (Object o = poll();;) { - if (o instanceof ByteBuf) { - writeAndRelease(nextByteBuf, (ByteBuf) o); - } else { - nextMsgBuf.add(o); - } - - if ((o = poll()) == null) { - break; - } - } - } - - return true; - } - - public boolean drainToNextOutbound(ChannelHandlerContext ctx) { - final int size = size(); - if (size == 0) { - return false; - } - - final int byteBufCnt = this.byteBufCnt; - if (byteBufCnt == 0 || ctx.nextOutboundBufferType() != BufType.BYTE) { - return drainTo(ctx.nextOutboundMessageBuffer()) > 0; - } - - final ByteBuf nextByteBuf = ctx.nextOutboundByteBuffer(); - if (byteBufCnt == size) { - // Contains only ByteBufs - for (Object o = poll();;) { - writeAndRelease(nextByteBuf, (ByteBuf) o); - if ((o = poll()) == null) { - break; - } - } - } else { - // Contains both ByteBufs and non-ByteBufs (0 < byteBufCnt < size()) - final MessageBuf nextMsgBuf = ctx.nextOutboundMessageBuffer(); - for (Object o = poll();;) { - if (o instanceof ByteBuf) { - writeAndRelease(nextByteBuf, (ByteBuf) o); - } else { - nextMsgBuf.add(o); - } - - if ((o = poll()) == null) { - break; - } - } - } - - return true; - } - - private static void writeAndRelease(ByteBuf dst, ByteBuf src) { - try { - dst.writeBytes(src, src.readerIndex(), src.readableBytes()); - } finally { - BufUtil.release(src); - } - } -} diff --git a/codec/src/main/java/io/netty/handler/codec/ReplayingDecoder.java b/codec/src/main/java/io/netty/handler/codec/ReplayingDecoder.java index f35ab7e8b6..f1f4025cb5 100644 --- a/codec/src/main/java/io/netty/handler/codec/ReplayingDecoder.java +++ b/codec/src/main/java/io/netty/handler/codec/ReplayingDecoder.java @@ -19,7 +19,9 @@ import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandler; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelPipeline; +import io.netty.channel.MessageList; import io.netty.util.Signal; +import io.netty.util.internal.StringUtil; /** * A specialized variation of {@link ByteToMessageDecoder} which enables implementation @@ -30,7 +32,7 @@ import io.netty.util.Signal; * implement the {@code decode()} and {@code decodeLast()} methods just like * all required bytes were received already, rather than checking the * availability of the required bytes. For example, the following - * {@link ByteToByteDecoder} implementation: + * {@link ByteToMessageDecoder} implementation: *
  * public class IntegerHeaderFrameDecoder extends {@link ByteToMessageDecoder}<{@link ByteBuf}> {
  *
@@ -226,7 +228,7 @@ import io.netty.util.Signal;
  * 

* If you are going to write a protocol multiplexer, you will probably want to * replace a {@link ReplayingDecoder} (protocol detector) with another - * {@link ReplayingDecoder}, {@link ByteToByteDecoder}, {@link ByteToMessageDecoder} or {@link MessageToMessageDecoder} + * {@link ReplayingDecoder}, {@link ByteToMessageDecoder} or {@link MessageToMessageDecoder} * (actual protocol decoder). * It is not possible to achieve this simply by calling * {@link ChannelPipeline#replace(ChannelHandler, String, ChannelHandler)}, but @@ -264,11 +266,9 @@ public abstract class ReplayingDecoder extends ByteToMessageDecoder { static final Signal REPLAY = new Signal(ReplayingDecoder.class.getName() + ".REPLAY"); - private ChannelHandlerContext ctx; private final ReplayingDecoderBuffer replayable = new ReplayingDecoderBuffer(); private S state; private int checkpoint = -1; - private boolean decodeWasNull; /** * Creates a new instance with no initial state (i.e: {@code null}). @@ -318,89 +318,47 @@ public abstract class ReplayingDecoder extends ByteToMessageDecoder { return oldState; } - /** - * Returns the actual number of readable bytes in the internal cumulative - * buffer of this decoder. You usually do not need to rely on this value - * to write a decoder. Use it only when you muse use it at your own risk. - * This method is a shortcut to {@link #internalBuffer() internalBuffer().readableBytes()}. - */ - protected int actualReadableBytes() { - return internalBuffer().readableBytes(); - } - - /** - * Returns the internal cumulative buffer of this decoder. You usually - * do not need to access the internal buffer directly to write a decoder. - * Use it only when you must use it at your own risk. - */ - protected ByteBuf internalBuffer() { - return ctx.inboundByteBuffer(); - } - - @Override - public void handlerAdded(ChannelHandlerContext ctx) throws Exception { - this.ctx = ctx; - } - - @Override - public final void discardInboundReadBytes(ChannelHandlerContext ctx) throws Exception { - ByteBuf in = ctx.inboundByteBuffer(); - final int oldReaderIndex = in.readerIndex(); - discardInboundReadBytes0(ctx); - final int newReaderIndex = in.readerIndex(); - checkpoint -= oldReaderIndex - newReaderIndex; - } - - protected void discardInboundReadBytes0(ChannelHandlerContext ctx) throws Exception { - super.discardInboundReadBytes(ctx); - } - @Override public void channelInactive(ChannelHandlerContext ctx) throws Exception { - OutputMessageBuf out = OutputMessageBuf.get(); + MessageList out = MessageList.newInstance(); try { replayable.terminate(); - ByteBuf in = internalBuffer(); - replayable.setCumulation(in); - if (in.isReadable()) { - callDecode(ctx, in); - } - + callDecode(ctx, internalBuffer(), out); decodeLast(ctx, replayable, out); } catch (Signal replay) { // Ignore replay.expect(REPLAY); - } catch (CodecException e) { + } catch (DecoderException e) { throw e; - } catch (Throwable cause) { - throw new DecoderException(cause); + } catch (Exception e) { + throw new DecoderException(e); } finally { - if (out.drainToNextInbound(ctx)) { - ctx.fireInboundBufferUpdated(); + if (cumulation != null) { + cumulation.release(); + cumulation = null; } + ctx.fireMessageReceived(out); ctx.fireChannelInactive(); } } @Override - protected void callDecode(ChannelHandlerContext ctx, ByteBuf buf) { - boolean wasNull = false; - ByteBuf in = internalBuffer(); + protected void callDecode(ChannelHandlerContext ctx, ByteBuf in, MessageList out) { replayable.setCumulation(in); - OutputMessageBuf out = OutputMessageBuf.get(); try { while (in.isReadable()) { int oldReaderIndex = checkpoint = in.readerIndex(); int outSize = out.size(); S oldState = state; + int oldInputLength = in.readableBytes(); try { decode(ctx, replayable, out); if (outSize == out.size()) { - wasNull = true; - if (oldReaderIndex == in.readerIndex() && oldState == state) { - throw new IllegalStateException( - "null cannot be returned if no data is consumed and state didn't change."); + if (oldInputLength == in.readableBytes() && oldState == state) { + throw new DecoderException( + StringUtil.simpleClassName(getClass()) + ".decode() must consume the inbound " + + "data or change its state if it did not decode anything."); } else { // Previous data has been discarded or caused state transition. // Probably it is reading on. @@ -419,43 +377,20 @@ public abstract class ReplayingDecoder extends ByteToMessageDecoder { } break; } - wasNull = false; if (oldReaderIndex == in.readerIndex() && oldState == state) { - throw new IllegalStateException( - "decode() method must consume at least one byte " + - "if it returned a decoded message (caused by: " + - getClass() + ')'); + throw new DecoderException( + StringUtil.simpleClassName(getClass()) + ".decode() method must consume the inbound data " + + "or change its state if it decoded something."); } if (isSingleDecode()) { break; } } - } catch (CodecException e) { + } catch (DecoderException e) { throw e; } catch (Throwable cause) { throw new DecoderException(cause); - } finally { - if (out.drainToNextInbound(ctx)) { - decodeWasNull = false; - ctx.fireInboundBufferUpdated(); - } else { - if (wasNull) { - decodeWasNull = true; - } - } } } - - @Override - public void channelReadSuspended(ChannelHandlerContext ctx) throws Exception { - if (decodeWasNull) { - decodeWasNull = false; - if (!ctx.channel().config().isAutoRead()) { - ctx.read(); - } - } - - super.channelReadSuspended(ctx); - } } diff --git a/codec/src/main/java/io/netty/handler/codec/ReplayingDecoderBuffer.java b/codec/src/main/java/io/netty/handler/codec/ReplayingDecoderBuffer.java index edfa277d8a..60d17fbfdb 100644 --- a/codec/src/main/java/io/netty/handler/codec/ReplayingDecoderBuffer.java +++ b/codec/src/main/java/io/netty/handler/codec/ReplayingDecoderBuffer.java @@ -15,7 +15,6 @@ */ package io.netty.handler.codec; -import io.netty.buffer.BufType; import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBufAllocator; import io.netty.buffer.ByteBufIndexFinder; @@ -81,11 +80,6 @@ final class ReplayingDecoderBuffer implements ByteBuf { return capacity(); } - @Override - public BufType type() { - return BufType.BYTE; - } - @Override public ByteBufAllocator alloc() { return buffer.alloc(); @@ -925,16 +919,6 @@ final class ReplayingDecoderBuffer implements ByteBuf { throw new UnreplayableOperationException(); } - @Override - public ByteBuf suspendIntermediaryDeallocations() { - throw new UnreplayableOperationException(); - } - - @Override - public ByteBuf resumeIntermediaryDeallocations() { - throw new UnreplayableOperationException(); - } - @Override public ByteBuf unwrap() { throw new UnreplayableOperationException(); diff --git a/codec/src/main/java/io/netty/handler/codec/base64/Base64Decoder.java b/codec/src/main/java/io/netty/handler/codec/base64/Base64Decoder.java index ff1eb4458d..f8b13edaa9 100644 --- a/codec/src/main/java/io/netty/handler/codec/base64/Base64Decoder.java +++ b/codec/src/main/java/io/netty/handler/codec/base64/Base64Decoder.java @@ -16,10 +16,10 @@ package io.netty.handler.codec.base64; import io.netty.buffer.ByteBuf; -import io.netty.buffer.MessageBuf; import io.netty.channel.ChannelHandler.Sharable; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelPipeline; +import io.netty.channel.MessageList; import io.netty.handler.codec.ByteToMessageDecoder; import io.netty.handler.codec.DelimiterBasedFrameDecoder; import io.netty.handler.codec.Delimiters; @@ -59,7 +59,7 @@ public class Base64Decoder extends MessageToMessageDecoder { } @Override - protected void decode(ChannelHandlerContext ctx, ByteBuf msg, MessageBuf out) throws Exception { + protected void decode(ChannelHandlerContext ctx, ByteBuf msg, MessageList out) throws Exception { out.add(Base64.decode(msg, msg.readerIndex(), msg.readableBytes(), dialect)); } } diff --git a/codec/src/main/java/io/netty/handler/codec/base64/Base64Encoder.java b/codec/src/main/java/io/netty/handler/codec/base64/Base64Encoder.java index b79b0fbe04..5af5b71065 100644 --- a/codec/src/main/java/io/netty/handler/codec/base64/Base64Encoder.java +++ b/codec/src/main/java/io/netty/handler/codec/base64/Base64Encoder.java @@ -18,11 +18,11 @@ package io.netty.handler.codec.base64; import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandler.Sharable; import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.ChannelHandlerUtil; -import io.netty.channel.ChannelOutboundMessageHandlerAdapter; import io.netty.channel.ChannelPipeline; +import io.netty.channel.MessageList; import io.netty.handler.codec.DelimiterBasedFrameDecoder; import io.netty.handler.codec.Delimiters; +import io.netty.handler.codec.MessageToMessageEncoder; /** * Encodes a {@link ByteBuf} into a Base64-encoded {@link ByteBuf}. @@ -39,7 +39,7 @@ import io.netty.handler.codec.Delimiters; * */ @Sharable -public class Base64Encoder extends ChannelOutboundMessageHandlerAdapter { +public class Base64Encoder extends MessageToMessageEncoder { private final boolean breakLines; private final Base64Dialect dialect; @@ -62,9 +62,7 @@ public class Base64Encoder extends ChannelOutboundMessageHandlerAdapter } @Override - public void flush(ChannelHandlerContext ctx, - ByteBuf msg) throws Exception { - ByteBuf buf = Base64.encode(msg, msg.readerIndex(), msg.readableBytes(), breakLines, dialect); - ChannelHandlerUtil.addToNextOutboundBuffer(ctx, buf); + protected void encode(ChannelHandlerContext ctx, ByteBuf msg, MessageList out) throws Exception { + out.add(Base64.encode(msg, msg.readerIndex(), msg.readableBytes(), breakLines, dialect)); } } diff --git a/codec/src/main/java/io/netty/handler/codec/bytes/ByteArrayDecoder.java b/codec/src/main/java/io/netty/handler/codec/bytes/ByteArrayDecoder.java index 1d0f8acf9e..a1d15b6d2f 100644 --- a/codec/src/main/java/io/netty/handler/codec/bytes/ByteArrayDecoder.java +++ b/codec/src/main/java/io/netty/handler/codec/bytes/ByteArrayDecoder.java @@ -16,9 +16,9 @@ package io.netty.handler.codec.bytes; import io.netty.buffer.ByteBuf; -import io.netty.buffer.MessageBuf; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelPipeline; +import io.netty.channel.MessageList; import io.netty.handler.codec.LengthFieldBasedFrameDecoder; import io.netty.handler.codec.LengthFieldPrepender; import io.netty.handler.codec.MessageToMessageDecoder; @@ -48,9 +48,8 @@ import io.netty.handler.codec.MessageToMessageDecoder; * */ public class ByteArrayDecoder extends MessageToMessageDecoder { - @Override - protected void decode(ChannelHandlerContext ctx, ByteBuf msg, MessageBuf out) throws Exception { + protected void decode(ChannelHandlerContext ctx, ByteBuf msg, MessageList out) throws Exception { byte[] array; if (msg.hasArray()) { if (msg.arrayOffset() == 0 && msg.readableBytes() == msg.capacity()) { diff --git a/codec/src/main/java/io/netty/handler/codec/bytes/ByteArrayEncoder.java b/codec/src/main/java/io/netty/handler/codec/bytes/ByteArrayEncoder.java index 9a0d8bf206..1014084e63 100644 --- a/codec/src/main/java/io/netty/handler/codec/bytes/ByteArrayEncoder.java +++ b/codec/src/main/java/io/netty/handler/codec/bytes/ByteArrayEncoder.java @@ -19,10 +19,11 @@ import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import io.netty.channel.ChannelHandler.Sharable; import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.ChannelOutboundMessageHandlerAdapter; import io.netty.channel.ChannelPipeline; +import io.netty.channel.MessageList; import io.netty.handler.codec.LengthFieldBasedFrameDecoder; import io.netty.handler.codec.LengthFieldPrepender; +import io.netty.handler.codec.MessageToMessageEncoder; /** * Encodes the requested array of bytes into a {@link ByteBuf}. @@ -49,23 +50,9 @@ import io.netty.handler.codec.LengthFieldPrepender; * */ @Sharable -public class ByteArrayEncoder extends ChannelOutboundMessageHandlerAdapter { - +public class ByteArrayEncoder extends MessageToMessageEncoder { @Override - public void flush(ChannelHandlerContext ctx, byte[] msg) throws Exception { - if (msg.length == 0) { - return; - } - - switch (ctx.nextOutboundBufferType()) { - case BYTE: - ctx.nextOutboundByteBuffer().writeBytes(msg); - break; - case MESSAGE: - ctx.nextOutboundMessageBuffer().add(Unpooled.wrappedBuffer(msg)); - break; - default: - throw new Error(); - } + protected void encode(ChannelHandlerContext ctx, byte[] msg, MessageList out) throws Exception { + out.add(Unpooled.wrappedBuffer(msg)); } } diff --git a/codec/src/main/java/io/netty/handler/codec/compression/CompressionException.java b/codec/src/main/java/io/netty/handler/codec/compression/CompressionException.java index 89f17b4198..167e45dd7d 100644 --- a/codec/src/main/java/io/netty/handler/codec/compression/CompressionException.java +++ b/codec/src/main/java/io/netty/handler/codec/compression/CompressionException.java @@ -15,13 +15,12 @@ */ package io.netty.handler.codec.compression; -import io.netty.handler.codec.CodecException; +import io.netty.handler.codec.EncoderException; /** - * An {@link CodecException} that is raised when compression or decompression - * failed. + * An {@link EncoderException} that is raised when compression failed. */ -public class CompressionException extends CodecException { +public class CompressionException extends EncoderException { private static final long serialVersionUID = 5603413481274811897L; diff --git a/codec/src/main/java/io/netty/handler/codec/compression/DecompressionException.java b/codec/src/main/java/io/netty/handler/codec/compression/DecompressionException.java new file mode 100644 index 0000000000..8fc016bf8d --- /dev/null +++ b/codec/src/main/java/io/netty/handler/codec/compression/DecompressionException.java @@ -0,0 +1,53 @@ +/* + * Copyright 2012 The Netty Project + * + * The Netty Project licenses this file to you under the Apache License, + * version 2.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +package io.netty.handler.codec.compression; + +import io.netty.handler.codec.DecoderException; + +/** + * A {@link DecoderException} that is raised when decompression failed. + */ +public class DecompressionException extends DecoderException { + + private static final long serialVersionUID = 3546272712208105199L; + + /** + * Creates a new instance. + */ + public DecompressionException() { + } + + /** + * Creates a new instance. + */ + public DecompressionException(String message, Throwable cause) { + super(message, cause); + } + + /** + * Creates a new instance. + */ + public DecompressionException(String message) { + super(message); + } + + /** + * Creates a new instance. + */ + public DecompressionException(Throwable cause) { + super(cause); + } +} diff --git a/codec/src/main/java/io/netty/handler/codec/compression/JZlibDecoder.java b/codec/src/main/java/io/netty/handler/codec/compression/JZlibDecoder.java index a4dfe4a0a9..ca9b39dd98 100644 --- a/codec/src/main/java/io/netty/handler/codec/compression/JZlibDecoder.java +++ b/codec/src/main/java/io/netty/handler/codec/compression/JZlibDecoder.java @@ -15,10 +15,11 @@ */ package io.netty.handler.codec.compression; +import com.jcraft.jzlib.Inflater; +import com.jcraft.jzlib.JZlib; import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; -import com.jcraft.jzlib.JZlib; -import com.jcraft.jzlib.Inflater; +import io.netty.channel.MessageList; public class JZlibDecoder extends ZlibDecoder { @@ -81,9 +82,7 @@ public class JZlibDecoder extends ZlibDecoder { } @Override - protected void decode( - ChannelHandlerContext ctx, - ByteBuf in, ByteBuf out) throws Exception { + protected void decode(ChannelHandlerContext ctx, ByteBuf in, MessageList out) throws Exception { if (!in.isReadable()) { return; @@ -92,14 +91,13 @@ public class JZlibDecoder extends ZlibDecoder { try { // Configure input. int inputLength = in.readableBytes(); - boolean inHasArray = in.hasArray(); z.avail_in = inputLength; - if (inHasArray) { + if (in.hasArray()) { z.next_in = in.array(); z.next_in_index = in.arrayOffset() + in.readerIndex(); } else { byte[] array = new byte[inputLength]; - in.readBytes(array); + in.getBytes(in.readerIndex(), array); z.next_in = array; z.next_in_index = 0; } @@ -107,32 +105,21 @@ public class JZlibDecoder extends ZlibDecoder { // Configure output. int maxOutputLength = inputLength << 1; - boolean outHasArray = out.hasArray(); - if (!outHasArray) { - z.next_out = new byte[maxOutputLength]; - } + ByteBuf decompressed = ctx.alloc().heapBuffer(maxOutputLength); try { loop: for (;;) { z.avail_out = maxOutputLength; - if (outHasArray) { - out.ensureWritable(maxOutputLength); - z.next_out = out.array(); - z.next_out_index = out.arrayOffset() + out.writerIndex(); - } else { - z.next_out_index = 0; - } + decompressed.ensureWritable(maxOutputLength); + z.next_out = decompressed.array(); + z.next_out_index = decompressed.arrayOffset() + decompressed.writerIndex(); int oldNextOutIndex = z.next_out_index; // Decompress 'in' into 'out' int resultCode = z.inflate(JZlib.Z_SYNC_FLUSH); int outputLength = z.next_out_index - oldNextOutIndex; if (outputLength > 0) { - if (outHasArray) { - out.writerIndex(out.writerIndex() + outputLength); - } else { - out.writeBytes(z.next_out, 0, outputLength); - } + decompressed.writerIndex(decompressed.writerIndex() + outputLength); } switch (resultCode) { @@ -162,8 +149,11 @@ public class JZlibDecoder extends ZlibDecoder { } } } finally { - if (inHasArray) { - in.skipBytes(z.next_in_index - oldNextInIndex); + in.skipBytes(z.next_in_index - oldNextInIndex); + if (decompressed.isReadable()) { + out.add(decompressed); + } else { + decompressed.release(); } } } finally { diff --git a/codec/src/main/java/io/netty/handler/codec/compression/JZlibEncoder.java b/codec/src/main/java/io/netty/handler/codec/compression/JZlibEncoder.java index 9a4d57a8a0..2a94ab2ef8 100644 --- a/codec/src/main/java/io/netty/handler/codec/compression/JZlibEncoder.java +++ b/codec/src/main/java/io/netty/handler/codec/compression/JZlibEncoder.java @@ -280,7 +280,7 @@ public class JZlibEncoder extends ZlibEncoder { z.next_in_index = in.arrayOffset() + in.readerIndex(); } else { byte[] array = new byte[inputLength]; - in.readBytes(array); + in.getBytes(in.readerIndex(), array); z.next_in = array; z.next_in_index = 0; } @@ -288,16 +288,10 @@ public class JZlibEncoder extends ZlibEncoder { // Configure output. int maxOutputLength = (int) Math.ceil(inputLength * 1.001) + 12; - boolean outHasArray = out.hasArray(); + ByteBuf compressed = ctx.alloc().heapBuffer(maxOutputLength); z.avail_out = maxOutputLength; - if (outHasArray) { - out.ensureWritable(maxOutputLength); - z.next_out = out.array(); - z.next_out_index = out.arrayOffset() + out.writerIndex(); - } else { - z.next_out = new byte[maxOutputLength]; - z.next_out_index = 0; - } + z.next_out = out.array(); + z.next_out_index = out.arrayOffset() + out.writerIndex(); int oldNextOutIndex = z.next_out_index; // Note that Z_PARTIAL_FLUSH has been deprecated. @@ -305,9 +299,7 @@ public class JZlibEncoder extends ZlibEncoder { try { resultCode = z.deflate(JZlib.Z_SYNC_FLUSH); } finally { - if (inHasArray) { - in.skipBytes(z.next_in_index - oldNextInIndex); - } + in.skipBytes(z.next_in_index - oldNextInIndex); } if (resultCode != JZlib.Z_OK) { @@ -316,11 +308,7 @@ public class JZlibEncoder extends ZlibEncoder { int outputLength = z.next_out_index - oldNextOutIndex; if (outputLength > 0) { - if (outHasArray) { - out.writerIndex(out.writerIndex() + outputLength); - } else { - out.writeBytes(z.next_out, 0, outputLength); - } + out.writerIndex(out.writerIndex() + outputLength); } } finally { // Deference the external references explicitly to tell the VM that diff --git a/codec/src/main/java/io/netty/handler/codec/compression/JdkZlibEncoder.java b/codec/src/main/java/io/netty/handler/codec/compression/JdkZlibEncoder.java index 638b9ff16f..e225e731e3 100644 --- a/codec/src/main/java/io/netty/handler/codec/compression/JdkZlibEncoder.java +++ b/codec/src/main/java/io/netty/handler/codec/compression/JdkZlibEncoder.java @@ -255,10 +255,7 @@ public class JdkZlibEncoder extends ZlibEncoder { deflater.end(); } - ctx.nextOutboundByteBuffer().writeBytes(footer); - ctx.flush(promise); - - return promise; + return ctx.write(footer, promise); } @Override diff --git a/codec/src/main/java/io/netty/handler/codec/compression/Snappy.java b/codec/src/main/java/io/netty/handler/codec/compression/Snappy.java index 4fd273d81e..3219f0b3ce 100644 --- a/codec/src/main/java/io/netty/handler/codec/compression/Snappy.java +++ b/codec/src/main/java/io/netty/handler/codec/compression/Snappy.java @@ -15,8 +15,8 @@ */ package io.netty.handler.codec.compression; -import io.netty.buffer.BufUtil; import io.netty.buffer.ByteBuf; +import io.netty.buffer.ByteBufUtil; import java.util.zip.CRC32; @@ -381,7 +381,7 @@ public class Snappy { } if (byteIndex >= 4) { - throw new CompressionException("Preamble is greater than 4 bytes"); + throw new DecompressionException("Preamble is greater than 4 bytes"); } } @@ -413,19 +413,19 @@ public class Snappy { if (in.readableBytes() < 2) { return NOT_ENOUGH_INPUT; } - length = BufUtil.swapShort(in.readShort()); + length = ByteBufUtil.swapShort(in.readShort()); break; case 62: if (in.readableBytes() < 3) { return NOT_ENOUGH_INPUT; } - length = BufUtil.swapMedium(in.readUnsignedMedium()); + length = ByteBufUtil.swapMedium(in.readUnsignedMedium()); break; case 64: if (in.readableBytes() < 4) { return NOT_ENOUGH_INPUT; } - length = BufUtil.swapInt(in.readInt()); + length = ByteBufUtil.swapInt(in.readInt()); break; default: length = tag >> 2 & 0x3F; @@ -452,7 +452,7 @@ public class Snappy { * @param out The output buffer to write to * @return The number of bytes appended to the output buffer, or -1 to indicate * "try again later" - * @throws CompressionException If the read offset is invalid + * @throws DecompressionException If the read offset is invalid */ private static int decodeCopyWith1ByteOffset(byte tag, ByteBuf in, ByteBuf out, int writtenSoFar) { if (!in.isReadable()) { @@ -494,7 +494,7 @@ public class Snappy { * the length and part of the offset * @param in The input buffer to read from * @param out The output buffer to write to - * @throws CompressionException If the read offset is invalid + * @throws DecompressionException If the read offset is invalid * @return The number of bytes appended to the output buffer, or -1 to indicate * "try again later" */ @@ -505,7 +505,7 @@ public class Snappy { int initialIndex = out.writerIndex(); int length = 1 + (tag >> 2 & 0x03f); - int offset = BufUtil.swapShort(in.readShort()); + int offset = ByteBufUtil.swapShort(in.readShort()); validateOffset(offset, writtenSoFar); @@ -540,7 +540,7 @@ public class Snappy { * @param out The output buffer to write to * @return The number of bytes appended to the output buffer, or -1 to indicate * "try again later" - * @throws CompressionException If the read offset is invalid + * @throws DecompressionException If the read offset is invalid */ private static int decodeCopyWith4ByteOffset(byte tag, ByteBuf in, ByteBuf out, int writtenSoFar) { if (in.readableBytes() < 4) { @@ -549,7 +549,7 @@ public class Snappy { int initialIndex = out.writerIndex(); int length = 1 + (tag >> 2 & 0x03F); - int offset = BufUtil.swapInt(in.readInt()); + int offset = ByteBufUtil.swapInt(in.readInt()); validateOffset(offset, writtenSoFar); @@ -580,19 +580,19 @@ public class Snappy { * * @param offset The offset extracted from the compressed reference * @param chunkSizeSoFar The number of bytes read so far from this chunk - * @throws CompressionException if the offset is invalid + * @throws DecompressionException if the offset is invalid */ private static void validateOffset(int offset, int chunkSizeSoFar) { if (offset > Short.MAX_VALUE) { - throw new CompressionException("Offset exceeds maximum permissible value"); + throw new DecompressionException("Offset exceeds maximum permissible value"); } if (offset <= 0) { - throw new CompressionException("Offset is less than minimum permissible value"); + throw new DecompressionException("Offset is less than minimum permissible value"); } if (offset > chunkSizeSoFar) { - throw new CompressionException("Offset exceeds size of chunk"); + throw new DecompressionException("Offset exceeds size of chunk"); } } @@ -636,7 +636,7 @@ public class Snappy { * * @param expectedChecksum The checksum decoded from the stream to compare against * @param data The input data to calculate the CRC32 checksum of - * @throws CompressionException If the calculated and supplied checksums do not match + * @throws DecompressionException If the calculated and supplied checksums do not match */ static void validateChecksum(int expectedChecksum, ByteBuf data) { validateChecksum(expectedChecksum, data, data.readerIndex(), data.readableBytes()); @@ -649,12 +649,12 @@ public class Snappy { * * @param expectedChecksum The checksum decoded from the stream to compare against * @param data The input data to calculate the CRC32 checksum of - * @throws CompressionException If the calculated and supplied checksums do not match + * @throws DecompressionException If the calculated and supplied checksums do not match */ static void validateChecksum(int expectedChecksum, ByteBuf data, int offset, int length) { final int actualChecksum = calculateChecksum(data, offset, length); if (actualChecksum != expectedChecksum) { - throw new CompressionException( + throw new DecompressionException( "mismatching checksum: " + Integer.toHexString(actualChecksum) + " (expected: " + Integer.toHexString(expectedChecksum) + ')'); } diff --git a/codec/src/main/java/io/netty/handler/codec/compression/SnappyFramedDecoder.java b/codec/src/main/java/io/netty/handler/codec/compression/SnappyFramedDecoder.java index d10c5b7999..c0fa5eae80 100644 --- a/codec/src/main/java/io/netty/handler/codec/compression/SnappyFramedDecoder.java +++ b/codec/src/main/java/io/netty/handler/codec/compression/SnappyFramedDecoder.java @@ -15,10 +15,11 @@ */ package io.netty.handler.codec.compression; -import io.netty.buffer.BufUtil; import io.netty.buffer.ByteBuf; +import io.netty.buffer.ByteBufUtil; import io.netty.channel.ChannelHandlerContext; -import io.netty.handler.codec.ByteToByteDecoder; +import io.netty.channel.MessageList; +import io.netty.handler.codec.ByteToMessageDecoder; import java.util.Arrays; @@ -35,7 +36,7 @@ import static io.netty.handler.codec.compression.Snappy.*; * use the {@link #SnappyFramedDecoder(boolean)} constructor with the argument * set to {@code true}. */ -public class SnappyFramedDecoder extends ByteToByteDecoder { +public class SnappyFramedDecoder extends ByteToMessageDecoder { enum ChunkType { STREAM_IDENTIFIER, COMPRESSED_DATA, @@ -68,14 +69,14 @@ public class SnappyFramedDecoder extends ByteToByteDecoder { * @param validateChecksums * If true, the checksum field will be validated against the actual * uncompressed data, and if the checksums do not match, a suitable - * {@link CompressionException} will be thrown + * {@link DecompressionException} will be thrown */ public SnappyFramedDecoder(boolean validateChecksums) { this.validateChecksums = validateChecksums; } @Override - protected void decode(ChannelHandlerContext ctx, ByteBuf in, ByteBuf out) throws Exception { + protected void decode(ChannelHandlerContext ctx, ByteBuf in, MessageList out) throws Exception { if (corrupted) { in.skipBytes(in.readableBytes()); return; @@ -92,12 +93,12 @@ public class SnappyFramedDecoder extends ByteToByteDecoder { final int chunkTypeVal = in.getUnsignedByte(idx); final ChunkType chunkType = mapChunkType((byte) chunkTypeVal); - final int chunkLength = BufUtil.swapMedium(in.getUnsignedMedium(idx + 1)); + final int chunkLength = ByteBufUtil.swapMedium(in.getUnsignedMedium(idx + 1)); switch (chunkType) { case STREAM_IDENTIFIER: if (chunkLength != SNAPPY.length) { - throw new CompressionException("Unexpected length of stream identifier: " + chunkLength); + throw new DecompressionException("Unexpected length of stream identifier: " + chunkLength); } if (inSize < 4 + SNAPPY.length) { @@ -108,7 +109,7 @@ public class SnappyFramedDecoder extends ByteToByteDecoder { in.skipBytes(4).readBytes(identifier); if (!Arrays.equals(identifier, SNAPPY)) { - throw new CompressionException("Unexpected stream identifier contents. Mismatched snappy " + + throw new DecompressionException("Unexpected stream identifier contents. Mismatched snappy " + "protocol version?"); } @@ -116,7 +117,7 @@ public class SnappyFramedDecoder extends ByteToByteDecoder { break; case RESERVED_SKIPPABLE: if (!started) { - throw new CompressionException("Received RESERVED_SKIPPABLE tag before STREAM_IDENTIFIER"); + throw new DecompressionException("Received RESERVED_SKIPPABLE tag before STREAM_IDENTIFIER"); } if (inSize < 4 + chunkLength) { @@ -130,14 +131,14 @@ public class SnappyFramedDecoder extends ByteToByteDecoder { // The spec mandates that reserved unskippable chunks must immediately // return an error, as we must assume that we cannot decode the stream // correctly - throw new CompressionException( + throw new DecompressionException( "Found reserved unskippable chunk type: 0x" + Integer.toHexString(chunkTypeVal)); case UNCOMPRESSED_DATA: if (!started) { - throw new CompressionException("Received UNCOMPRESSED_DATA tag before STREAM_IDENTIFIER"); + throw new DecompressionException("Received UNCOMPRESSED_DATA tag before STREAM_IDENTIFIER"); } if (chunkLength > 65536 + 4) { - throw new CompressionException("Received UNCOMPRESSED_DATA larger than 65540 bytes"); + throw new DecompressionException("Received UNCOMPRESSED_DATA larger than 65540 bytes"); } if (inSize < 4 + chunkLength) { @@ -146,16 +147,16 @@ public class SnappyFramedDecoder extends ByteToByteDecoder { in.skipBytes(4); if (validateChecksums) { - int checksum = BufUtil.swapInt(in.readInt()); + int checksum = ByteBufUtil.swapInt(in.readInt()); validateChecksum(checksum, in, in.readerIndex(), chunkLength - 4); } else { in.skipBytes(4); } - out.writeBytes(in, chunkLength - 4); + out.add(in.readSlice(chunkLength - 4).retain()); break; case COMPRESSED_DATA: if (!started) { - throw new CompressionException("Received COMPRESSED_DATA tag before STREAM_IDENTIFIER"); + throw new DecompressionException("Received COMPRESSED_DATA tag before STREAM_IDENTIFIER"); } if (inSize < 4 + chunkLength) { @@ -163,21 +164,21 @@ public class SnappyFramedDecoder extends ByteToByteDecoder { } in.skipBytes(4); - int checksum = BufUtil.swapInt(in.readInt()); + int checksum = ByteBufUtil.swapInt(in.readInt()); + ByteBuf uncompressed = ctx.alloc().buffer(0); if (validateChecksums) { int oldWriterIndex = in.writerIndex(); - int uncompressedStart = out.writerIndex(); try { in.writerIndex(in.readerIndex() + chunkLength - 4); - snappy.decode(in, out); + snappy.decode(in, uncompressed); } finally { in.writerIndex(oldWriterIndex); } - int uncompressedLength = out.writerIndex() - uncompressedStart; - validateChecksum(checksum, out, uncompressedStart, uncompressedLength); + validateChecksum(checksum, uncompressed, 0, uncompressed.writerIndex()); } else { - snappy.decode(in.readSlice(chunkLength - 4), out); + snappy.decode(in.readSlice(chunkLength - 4), uncompressed); } + out.add(uncompressed); snappy.reset(); break; } diff --git a/codec/src/main/java/io/netty/handler/codec/compression/SnappyFramedEncoder.java b/codec/src/main/java/io/netty/handler/codec/compression/SnappyFramedEncoder.java index b7f22a0900..b22a026c2c 100644 --- a/codec/src/main/java/io/netty/handler/codec/compression/SnappyFramedEncoder.java +++ b/codec/src/main/java/io/netty/handler/codec/compression/SnappyFramedEncoder.java @@ -15,10 +15,10 @@ */ package io.netty.handler.codec.compression; -import io.netty.buffer.BufUtil; import io.netty.buffer.ByteBuf; +import io.netty.buffer.ByteBufUtil; import io.netty.channel.ChannelHandlerContext; -import io.netty.handler.codec.ByteToByteEncoder; +import io.netty.handler.codec.MessageToByteEncoder; import static io.netty.handler.codec.compression.Snappy.*; @@ -27,7 +27,7 @@ import static io.netty.handler.codec.compression.Snappy.*; * * See http://code.google.com/p/snappy/source/browse/trunk/framing_format.txt */ -public class SnappyFramedEncoder extends ByteToByteEncoder { +public class SnappyFramedEncoder extends MessageToByteEncoder { /** * The minimum amount that we'll consider actually attempting to compress. * This value is preamble + the minimum length our Snappy service will @@ -99,7 +99,7 @@ public class SnappyFramedEncoder extends ByteToByteEncoder { if (chunkLength >>> 24 != 0) { throw new CompressionException("compressed data too large: " + chunkLength); } - out.setMedium(lengthIdx, BufUtil.swapMedium(chunkLength)); + out.setMedium(lengthIdx, ByteBufUtil.swapMedium(chunkLength)); } /** @@ -109,7 +109,7 @@ public class SnappyFramedEncoder extends ByteToByteEncoder { * @param chunkLength The length to write */ private static void writeChunkLength(ByteBuf out, int chunkLength) { - out.writeMedium(BufUtil.swapMedium(chunkLength)); + out.writeMedium(ByteBufUtil.swapMedium(chunkLength)); } /** @@ -119,6 +119,6 @@ public class SnappyFramedEncoder extends ByteToByteEncoder { * @param out The output buffer to write the checksum to */ private static void calculateAndWriteChecksum(ByteBuf slice, ByteBuf out) { - out.writeInt(BufUtil.swapInt(calculateChecksum(slice))); + out.writeInt(ByteBufUtil.swapInt(calculateChecksum(slice))); } } diff --git a/codec/src/main/java/io/netty/handler/codec/compression/ZlibDecoder.java b/codec/src/main/java/io/netty/handler/codec/compression/ZlibDecoder.java index 550de06609..d01bc6b4de 100644 --- a/codec/src/main/java/io/netty/handler/codec/compression/ZlibDecoder.java +++ b/codec/src/main/java/io/netty/handler/codec/compression/ZlibDecoder.java @@ -16,12 +16,12 @@ package io.netty.handler.codec.compression; import io.netty.buffer.ByteBuf; -import io.netty.handler.codec.ByteToByteDecoder; +import io.netty.handler.codec.ByteToMessageDecoder; /** * Decompresses a {@link ByteBuf} using the deflate algorithm. */ -public abstract class ZlibDecoder extends ByteToByteDecoder { +public abstract class ZlibDecoder extends ByteToMessageDecoder { /** * Returns {@code true} if and only if the end of the compressed stream diff --git a/codec/src/main/java/io/netty/handler/codec/compression/ZlibEncoder.java b/codec/src/main/java/io/netty/handler/codec/compression/ZlibEncoder.java index 90c1b7ff45..c45d949658 100644 --- a/codec/src/main/java/io/netty/handler/codec/compression/ZlibEncoder.java +++ b/codec/src/main/java/io/netty/handler/codec/compression/ZlibEncoder.java @@ -18,12 +18,12 @@ package io.netty.handler.codec.compression; import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelPromise; -import io.netty.handler.codec.ByteToByteEncoder; +import io.netty.handler.codec.MessageToByteEncoder; /** * Compresses a {@link ByteBuf} using the deflate algorithm. */ -public abstract class ZlibEncoder extends ByteToByteEncoder { +public abstract class ZlibEncoder extends MessageToByteEncoder { /** * Returns {@code true} if and only if the end of the compressed stream diff --git a/codec/src/main/java/io/netty/handler/codec/marshalling/CompatibleMarshallingDecoder.java b/codec/src/main/java/io/netty/handler/codec/marshalling/CompatibleMarshallingDecoder.java index 7af3ebd75e..1551203d64 100644 --- a/codec/src/main/java/io/netty/handler/codec/marshalling/CompatibleMarshallingDecoder.java +++ b/codec/src/main/java/io/netty/handler/codec/marshalling/CompatibleMarshallingDecoder.java @@ -16,9 +16,9 @@ package io.netty.handler.codec.marshalling; import io.netty.buffer.ByteBuf; -import io.netty.buffer.MessageBuf; import io.netty.channel.Channel; import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.MessageList; import io.netty.handler.codec.ReplayingDecoder; import io.netty.handler.codec.TooLongFrameException; import org.jboss.marshalling.ByteInput; @@ -55,7 +55,7 @@ public class CompatibleMarshallingDecoder extends ReplayingDecoder { } @Override - protected void decode(ChannelHandlerContext ctx, ByteBuf buffer, MessageBuf out) throws Exception { + protected void decode(ChannelHandlerContext ctx, ByteBuf buffer, MessageList out) throws Exception { if (discardingTooLongFrame) { buffer.skipBytes(actualReadableBytes()); checkpoint(); @@ -83,7 +83,7 @@ public class CompatibleMarshallingDecoder extends ReplayingDecoder { } @Override - protected void decodeLast(ChannelHandlerContext ctx, ByteBuf buffer, MessageBuf out) throws Exception { + protected void decodeLast(ChannelHandlerContext ctx, ByteBuf buffer, MessageList out) throws Exception { switch (buffer.readableBytes()) { case 0: return; diff --git a/codec/src/main/java/io/netty/handler/codec/protobuf/ProtobufDecoder.java b/codec/src/main/java/io/netty/handler/codec/protobuf/ProtobufDecoder.java index 7bce890497..0e5ea7fd05 100644 --- a/codec/src/main/java/io/netty/handler/codec/protobuf/ProtobufDecoder.java +++ b/codec/src/main/java/io/netty/handler/codec/protobuf/ProtobufDecoder.java @@ -19,10 +19,10 @@ import com.google.protobuf.ExtensionRegistry; import com.google.protobuf.Message; import com.google.protobuf.MessageLite; import io.netty.buffer.ByteBuf; -import io.netty.buffer.MessageBuf; import io.netty.channel.ChannelHandler.Sharable; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelPipeline; +import io.netty.channel.MessageList; import io.netty.handler.codec.ByteToMessageDecoder; import io.netty.handler.codec.LengthFieldBasedFrameDecoder; import io.netty.handler.codec.LengthFieldPrepender; @@ -95,7 +95,7 @@ public class ProtobufDecoder extends MessageToMessageDecoder { } @Override - protected void decode(ChannelHandlerContext ctx, ByteBuf msg, MessageBuf out) throws Exception { + protected void decode(ChannelHandlerContext ctx, ByteBuf msg, MessageList out) throws Exception { final byte[] array; final int offset; final int length = msg.readableBytes(); diff --git a/codec/src/main/java/io/netty/handler/codec/protobuf/ProtobufEncoder.java b/codec/src/main/java/io/netty/handler/codec/protobuf/ProtobufEncoder.java index 874f402af6..27f1e96e3c 100644 --- a/codec/src/main/java/io/netty/handler/codec/protobuf/ProtobufEncoder.java +++ b/codec/src/main/java/io/netty/handler/codec/protobuf/ProtobufEncoder.java @@ -19,10 +19,10 @@ import com.google.protobuf.Message; import com.google.protobuf.MessageLite; import com.google.protobuf.MessageLiteOrBuilder; import io.netty.buffer.ByteBuf; -import io.netty.buffer.MessageBuf; import io.netty.channel.ChannelHandler.Sharable; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelPipeline; +import io.netty.channel.MessageList; import io.netty.handler.codec.LengthFieldBasedFrameDecoder; import io.netty.handler.codec.LengthFieldPrepender; import io.netty.handler.codec.MessageToMessageEncoder; @@ -58,10 +58,9 @@ import static io.netty.buffer.Unpooled.*; */ @Sharable public class ProtobufEncoder extends MessageToMessageEncoder { - @Override - protected void encode(ChannelHandlerContext ctx, MessageLiteOrBuilder msg, MessageBuf out) - throws Exception { + protected void encode( + ChannelHandlerContext ctx, MessageLiteOrBuilder msg, MessageList out) throws Exception { if (msg instanceof MessageLite) { out.add(wrappedBuffer(((MessageLite) msg).toByteArray())); return; diff --git a/codec/src/main/java/io/netty/handler/codec/protobuf/ProtobufVarint32FrameDecoder.java b/codec/src/main/java/io/netty/handler/codec/protobuf/ProtobufVarint32FrameDecoder.java index c9b0059112..b599f2ca56 100644 --- a/codec/src/main/java/io/netty/handler/codec/protobuf/ProtobufVarint32FrameDecoder.java +++ b/codec/src/main/java/io/netty/handler/codec/protobuf/ProtobufVarint32FrameDecoder.java @@ -17,8 +17,8 @@ package io.netty.handler.codec.protobuf; import com.google.protobuf.CodedInputStream; import io.netty.buffer.ByteBuf; -import io.netty.buffer.MessageBuf; import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.MessageList; import io.netty.handler.codec.ByteToMessageDecoder; import io.netty.handler.codec.CorruptedFrameException; @@ -43,7 +43,7 @@ public class ProtobufVarint32FrameDecoder extends ByteToMessageDecoder { // (just like LengthFieldBasedFrameDecoder) @Override - protected void decode(ChannelHandlerContext ctx, ByteBuf in, MessageBuf out) throws Exception { + protected void decode(ChannelHandlerContext ctx, ByteBuf in, MessageList out) throws Exception { in.markReaderIndex(); final byte[] buf = new byte[5]; for (int i = 0; i < buf.length; i ++) { diff --git a/codec/src/main/java/io/netty/handler/codec/string/StringDecoder.java b/codec/src/main/java/io/netty/handler/codec/string/StringDecoder.java index 2f465866fc..cfa9324583 100644 --- a/codec/src/main/java/io/netty/handler/codec/string/StringDecoder.java +++ b/codec/src/main/java/io/netty/handler/codec/string/StringDecoder.java @@ -16,10 +16,10 @@ package io.netty.handler.codec.string; import io.netty.buffer.ByteBuf; -import io.netty.buffer.MessageBuf; import io.netty.channel.ChannelHandler.Sharable; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelPipeline; +import io.netty.channel.MessageList; import io.netty.handler.codec.ByteToMessageDecoder; import io.netty.handler.codec.DelimiterBasedFrameDecoder; import io.netty.handler.codec.LineBasedFrameDecoder; @@ -75,7 +75,7 @@ public class StringDecoder extends MessageToMessageDecoder { } @Override - protected void decode(ChannelHandlerContext ctx, ByteBuf msg, MessageBuf out) throws Exception { + protected void decode(ChannelHandlerContext ctx, ByteBuf msg, MessageList out) throws Exception { out.add(msg.toString(charset)); } } diff --git a/codec/src/main/java/io/netty/handler/codec/string/StringEncoder.java b/codec/src/main/java/io/netty/handler/codec/string/StringEncoder.java index af6188f0f1..3c2059fe66 100644 --- a/codec/src/main/java/io/netty/handler/codec/string/StringEncoder.java +++ b/codec/src/main/java/io/netty/handler/codec/string/StringEncoder.java @@ -19,9 +19,9 @@ import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import io.netty.channel.ChannelHandler.Sharable; import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.ChannelOutboundMessageHandlerAdapter; import io.netty.channel.ChannelPipeline; import io.netty.handler.codec.LineBasedFrameDecoder; +import io.netty.handler.codec.MessageToByteEncoder; import java.nio.charset.Charset; @@ -47,7 +47,7 @@ import java.nio.charset.Charset; * */ @Sharable -public class StringEncoder extends ChannelOutboundMessageHandlerAdapter { +public class StringEncoder extends MessageToByteEncoder { // TODO Use CharsetEncoder instead. private final Charset charset; @@ -70,20 +70,12 @@ public class StringEncoder extends ChannelOutboundMessageHandlerAdapter out) { + protected void decode(ChannelHandlerContext ctx, ByteBuf in, MessageList out) { ByteBuf msg = in.readBytes(in.bytesBefore(ByteBufIndexFinder.LF)); in.skipBytes(1); out.add(msg); @@ -65,7 +65,7 @@ public class ReplayingDecoderTest { @Test public void testReplacement() throws Exception { - EmbeddedByteChannel ch = new EmbeddedByteChannel(new BloatedLineDecoder()); + EmbeddedChannel ch = new EmbeddedChannel(new BloatedLineDecoder()); // "AB" should be forwarded to LineDecoder by BloatedLineDecoder. ch.writeInbound(Unpooled.wrappedBuffer(new byte[]{'A', 'B'})); @@ -79,10 +79,11 @@ public class ReplayingDecoderTest { assertNull(ch.readInbound()); } - private static final class BloatedLineDecoder extends ChannelInboundByteHandlerAdapter { + private static final class BloatedLineDecoder extends ChannelInboundHandlerAdapter { @Override - protected void inboundBufferUpdated(ChannelHandlerContext ctx, ByteBuf in) throws Exception { + public void messageReceived(ChannelHandlerContext ctx, MessageList msgs) throws Exception { ctx.pipeline().replace(this, "less-bloated", new LineDecoder()); + ctx.pipeline().fireMessageReceived(msgs); } } @@ -90,7 +91,7 @@ public class ReplayingDecoderTest { public void testSingleDecode() throws Exception { LineDecoder decoder = new LineDecoder(); decoder.setSingleDecode(true); - EmbeddedByteChannel ch = new EmbeddedByteChannel(decoder); + EmbeddedChannel ch = new EmbeddedChannel(decoder); // "C\n" should be appended to "AB" so that LineDecoder decodes it correctly. ch.writeInbound(Unpooled.wrappedBuffer(new byte[]{'C', '\n' , 'B', '\n'})); diff --git a/codec/src/test/java/io/netty/handler/codec/bytes/ByteArrayDecoderTest.java b/codec/src/test/java/io/netty/handler/codec/bytes/ByteArrayDecoderTest.java index 0f390249ca..acec3cbf41 100644 --- a/codec/src/test/java/io/netty/handler/codec/bytes/ByteArrayDecoderTest.java +++ b/codec/src/test/java/io/netty/handler/codec/bytes/ByteArrayDecoderTest.java @@ -15,7 +15,7 @@ */ package io.netty.handler.codec.bytes; -import io.netty.channel.embedded.EmbeddedMessageChannel; +import io.netty.channel.embedded.EmbeddedChannel; import io.netty.util.internal.EmptyArrays; import org.junit.Before; import org.junit.Test; @@ -31,11 +31,11 @@ import static org.junit.Assert.*; @SuppressWarnings("ZeroLengthArrayAllocation") public class ByteArrayDecoderTest { - private EmbeddedMessageChannel ch; + private EmbeddedChannel ch; @Before public void setUp() { - ch = new EmbeddedMessageChannel(new ByteArrayDecoder()); + ch = new EmbeddedChannel(new ByteArrayDecoder()); } @Test diff --git a/codec/src/test/java/io/netty/handler/codec/bytes/ByteArrayEncoderTest.java b/codec/src/test/java/io/netty/handler/codec/bytes/ByteArrayEncoderTest.java index c190ee3949..9e46212819 100644 --- a/codec/src/test/java/io/netty/handler/codec/bytes/ByteArrayEncoderTest.java +++ b/codec/src/test/java/io/netty/handler/codec/bytes/ByteArrayEncoderTest.java @@ -16,7 +16,8 @@ package io.netty.handler.codec.bytes; import io.netty.buffer.ByteBuf; -import io.netty.channel.embedded.EmbeddedMessageChannel; +import io.netty.buffer.Unpooled; +import io.netty.channel.embedded.EmbeddedChannel; import io.netty.util.internal.EmptyArrays; import org.junit.Before; import org.junit.Test; @@ -31,11 +32,11 @@ import static org.junit.Assert.*; @SuppressWarnings("ZeroLengthArrayAllocation") public class ByteArrayEncoderTest { - private EmbeddedMessageChannel ch; + private EmbeddedChannel ch; @Before public void setUp() { - ch = new EmbeddedMessageChannel(new ByteArrayEncoder()); + ch = new EmbeddedChannel(new ByteArrayEncoder()); } @Test @@ -49,7 +50,7 @@ public class ByteArrayEncoderTest { @Test public void testEncodeEmpty() { ch.writeOutbound(EmptyArrays.EMPTY_BYTES); - assertThat(ch.readOutbound(), nullValue()); + assertThat((ByteBuf) ch.readOutbound(), is(Unpooled.EMPTY_BUFFER)); } @Test diff --git a/codec/src/test/java/io/netty/handler/codec/compression/JZlibTest.java b/codec/src/test/java/io/netty/handler/codec/compression/JZlibTest.java index a8477f91d5..faecedd859 100644 --- a/codec/src/test/java/io/netty/handler/codec/compression/JZlibTest.java +++ b/codec/src/test/java/io/netty/handler/codec/compression/JZlibTest.java @@ -17,9 +17,8 @@ package io.netty.handler.codec.compression; import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; -import org.junit.After; +import io.netty.channel.embedded.EmbeddedChannel; import org.junit.Test; -import io.netty.channel.embedded.EmbeddedByteChannel; import static org.junit.Assert.*; @@ -29,26 +28,23 @@ public class JZlibTest { public void testZLIB() throws Exception { ByteBuf data = Unpooled.wrappedBuffer("test".getBytes()); - EmbeddedByteChannel chEncoder = - new EmbeddedByteChannel(new JZlibEncoder(ZlibWrapper.ZLIB)); + EmbeddedChannel chEncoder = new EmbeddedChannel(new JZlibEncoder(ZlibWrapper.ZLIB)); chEncoder.writeOutbound(data.copy()); assertTrue(chEncoder.finish()); - byte[] deflatedData = chEncoder.readOutbound().array(); + ByteBuf deflatedData = (ByteBuf) chEncoder.readOutbound(); - EmbeddedByteChannel chDecoderZlib = - new EmbeddedByteChannel(new JZlibDecoder(ZlibWrapper.ZLIB)); + EmbeddedChannel chDecoderZlib = new EmbeddedChannel(new JZlibDecoder(ZlibWrapper.ZLIB)); - chDecoderZlib.writeInbound(Unpooled.wrappedBuffer(deflatedData)); + chDecoderZlib.writeInbound(deflatedData.copy()); assertTrue(chDecoderZlib.finish()); assertEquals(data, chDecoderZlib.readInbound()); - EmbeddedByteChannel chDecoderZlibOrNone = - new EmbeddedByteChannel(new JZlibDecoder(ZlibWrapper.ZLIB_OR_NONE)); + EmbeddedChannel chDecoderZlibOrNone = new EmbeddedChannel(new JZlibDecoder(ZlibWrapper.ZLIB_OR_NONE)); - chDecoderZlibOrNone.writeInbound(Unpooled.wrappedBuffer(deflatedData)); + chDecoderZlibOrNone.writeInbound(deflatedData); assertTrue(chDecoderZlibOrNone.finish()); assertEquals(data, chDecoderZlibOrNone.readInbound()); @@ -58,26 +54,24 @@ public class JZlibTest { public void testNONE() throws Exception { ByteBuf data = Unpooled.wrappedBuffer("test".getBytes()); - EmbeddedByteChannel chEncoder = - new EmbeddedByteChannel(new JZlibEncoder(ZlibWrapper.NONE)); + EmbeddedChannel chEncoder = new EmbeddedChannel(new JZlibEncoder(ZlibWrapper.NONE)); chEncoder.writeOutbound(data.copy()); assertTrue(chEncoder.finish()); - byte[] deflatedData = chEncoder.readOutbound().array(); + ByteBuf deflatedData = (ByteBuf) chEncoder.readOutbound(); - EmbeddedByteChannel chDecoderZlibNone = - new EmbeddedByteChannel(new JZlibDecoder(ZlibWrapper.NONE)); + EmbeddedChannel chDecoderZlibNone = new EmbeddedChannel(new JZlibDecoder(ZlibWrapper.NONE)); - chDecoderZlibNone.writeInbound(Unpooled.wrappedBuffer(deflatedData)); + chDecoderZlibNone.writeInbound(deflatedData.copy()); assertTrue(chDecoderZlibNone.finish()); assertEquals(data, chDecoderZlibNone.readInbound()); - EmbeddedByteChannel chDecoderZlibOrNone = - new EmbeddedByteChannel(new JZlibDecoder(ZlibWrapper.ZLIB_OR_NONE)); + EmbeddedChannel chDecoderZlibOrNone = + new EmbeddedChannel(new JZlibDecoder(ZlibWrapper.ZLIB_OR_NONE)); - chDecoderZlibOrNone.writeInbound(Unpooled.wrappedBuffer(deflatedData)); + chDecoderZlibOrNone.writeInbound(deflatedData); assertTrue(chDecoderZlibOrNone.finish()); assertEquals(data, chDecoderZlibOrNone.readInbound()); @@ -87,26 +81,24 @@ public class JZlibTest { public void testGZIP() throws Exception { ByteBuf data = Unpooled.wrappedBuffer("test".getBytes()); - EmbeddedByteChannel chEncoder = - new EmbeddedByteChannel(new JZlibEncoder(ZlibWrapper.GZIP)); + EmbeddedChannel chEncoder = new EmbeddedChannel(new JZlibEncoder(ZlibWrapper.GZIP)); chEncoder.writeOutbound(data.copy()); assertTrue(chEncoder.finish()); - byte[] deflatedData = chEncoder.readOutbound().array(); + ByteBuf deflatedData = (ByteBuf) chEncoder.readOutbound(); - EmbeddedByteChannel chDecoderGZip = - new EmbeddedByteChannel(new JZlibDecoder(ZlibWrapper.GZIP)); + EmbeddedChannel chDecoderGZip = new EmbeddedChannel(new JZlibDecoder(ZlibWrapper.GZIP)); - chDecoderGZip.writeInbound(Unpooled.wrappedBuffer(deflatedData)); + chDecoderGZip.writeInbound(deflatedData.copy()); assertTrue(chDecoderGZip.finish()); assertEquals(data, chDecoderGZip.readInbound()); - EmbeddedByteChannel chDecoderZlibOrNone = - new EmbeddedByteChannel(new JZlibDecoder(ZlibWrapper.ZLIB_OR_NONE)); + EmbeddedChannel chDecoderZlibOrNone = + new EmbeddedChannel(new JZlibDecoder(ZlibWrapper.ZLIB_OR_NONE)); - chDecoderZlibOrNone.writeInbound(Unpooled.wrappedBuffer(deflatedData)); + chDecoderZlibOrNone.writeInbound(deflatedData); assertTrue(chDecoderZlibOrNone.finish()); assertEquals(data, chDecoderZlibOrNone.readInbound()); diff --git a/codec/src/test/java/io/netty/handler/codec/compression/SnappyFramedDecoderTest.java b/codec/src/test/java/io/netty/handler/codec/compression/SnappyFramedDecoderTest.java index 37d068c34a..2b25544309 100644 --- a/codec/src/test/java/io/netty/handler/codec/compression/SnappyFramedDecoderTest.java +++ b/codec/src/test/java/io/netty/handler/codec/compression/SnappyFramedDecoderTest.java @@ -17,21 +17,21 @@ package io.netty.handler.codec.compression; import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; -import io.netty.channel.embedded.EmbeddedByteChannel; +import io.netty.channel.embedded.EmbeddedChannel; import org.junit.Before; import org.junit.Test; import static org.junit.Assert.*; public class SnappyFramedDecoderTest { - private EmbeddedByteChannel channel; + private EmbeddedChannel channel; @Before public void initChannel() { - channel = new EmbeddedByteChannel(new SnappyFramedDecoder()); + channel = new EmbeddedChannel(new SnappyFramedDecoder()); } - @Test(expected = CompressionException.class) + @Test(expected = DecompressionException.class) public void testReservedUnskippableChunkTypeCausesError() throws Exception { ByteBuf in = Unpooled.wrappedBuffer(new byte[] { 0x03, 0x01, 0x00, 0x00, 0x00 @@ -40,7 +40,7 @@ public class SnappyFramedDecoderTest { channel.writeInbound(in); } - @Test(expected = CompressionException.class) + @Test(expected = DecompressionException.class) public void testInvalidStreamIdentifierLength() throws Exception { ByteBuf in = Unpooled.wrappedBuffer(new byte[] { -0x80, 0x05, 0x00, 0x00, 'n', 'e', 't', 't', 'y' @@ -49,7 +49,7 @@ public class SnappyFramedDecoderTest { channel.writeInbound(in); } - @Test(expected = CompressionException.class) + @Test(expected = DecompressionException.class) public void testInvalidStreamIdentifierValue() throws Exception { ByteBuf in = Unpooled.wrappedBuffer(new byte[] { -0x80, 0x06, 0x00, 0x00, 's', 'n', 'e', 't', 't', 'y' @@ -58,7 +58,7 @@ public class SnappyFramedDecoderTest { channel.writeInbound(in); } - @Test(expected = CompressionException.class) + @Test(expected = DecompressionException.class) public void testReservedSkippableBeforeStreamIdentifier() throws Exception { ByteBuf in = Unpooled.wrappedBuffer(new byte[] { -0x7f, 0x06, 0x00, 0x00, 's', 'n', 'e', 't', 't', 'y' @@ -67,7 +67,7 @@ public class SnappyFramedDecoderTest { channel.writeInbound(in); } - @Test(expected = CompressionException.class) + @Test(expected = DecompressionException.class) public void testUncompressedDataBeforeStreamIdentifier() throws Exception { ByteBuf in = Unpooled.wrappedBuffer(new byte[] { 0x01, 0x05, 0x00, 0x00, 'n', 'e', 't', 't', 'y' @@ -76,7 +76,7 @@ public class SnappyFramedDecoderTest { channel.writeInbound(in); } - @Test(expected = CompressionException.class) + @Test(expected = DecompressionException.class) public void testCompressedDataBeforeStreamIdentifier() throws Exception { ByteBuf in = Unpooled.wrappedBuffer(new byte[] { 0x00, 0x05, 0x00, 0x00, 'n', 'e', 't', 't', 'y' @@ -130,9 +130,9 @@ public class SnappyFramedDecoderTest { // The following two tests differ in only the checksum provided for the literal // uncompressed string "netty" - @Test(expected = CompressionException.class) + @Test(expected = DecompressionException.class) public void testInvalidChecksumThrowsException() throws Exception { - EmbeddedByteChannel channel = new EmbeddedByteChannel(new SnappyFramedDecoder(true)); + EmbeddedChannel channel = new EmbeddedChannel(new SnappyFramedDecoder(true)); // checksum here is presented as 0 ByteBuf in = Unpooled.wrappedBuffer(new byte[] { @@ -145,7 +145,7 @@ public class SnappyFramedDecoderTest { @Test public void testInvalidChecksumDoesNotThrowException() throws Exception { - EmbeddedByteChannel channel = new EmbeddedByteChannel(new SnappyFramedDecoder(true)); + EmbeddedChannel channel = new EmbeddedChannel(new SnappyFramedDecoder(true)); // checksum here is presented as -1568496083 (little endian) ByteBuf in = Unpooled.wrappedBuffer(new byte[] { diff --git a/codec/src/test/java/io/netty/handler/codec/compression/SnappyFramedEncoderTest.java b/codec/src/test/java/io/netty/handler/codec/compression/SnappyFramedEncoderTest.java index 661a99159c..7dfde03d91 100644 --- a/codec/src/test/java/io/netty/handler/codec/compression/SnappyFramedEncoderTest.java +++ b/codec/src/test/java/io/netty/handler/codec/compression/SnappyFramedEncoderTest.java @@ -16,19 +16,20 @@ package io.netty.handler.codec.compression; import io.netty.buffer.ByteBuf; +import io.netty.buffer.CompositeByteBuf; import io.netty.buffer.Unpooled; -import io.netty.channel.embedded.EmbeddedByteChannel; +import io.netty.channel.embedded.EmbeddedChannel; import org.junit.Before; import org.junit.Test; import static org.junit.Assert.*; public class SnappyFramedEncoderTest { - private EmbeddedByteChannel channel; + private EmbeddedChannel channel; @Before public void setUp() { - channel = new EmbeddedByteChannel(new SnappyFramedEncoder()); + channel = new EmbeddedChannel(new SnappyFramedEncoder()); } @Test @@ -83,7 +84,17 @@ public class SnappyFramedEncoderTest { 0x01, 0x09, 0x00, 0x00, 0x2d, -0x5a, -0x7e, -0x5e, 'n', 'e', 't', 't', 'y', 0x01, 0x09, 0x00, 0x00, 0x2d, -0x5a, -0x7e, -0x5e, 'n', 'e', 't', 't', 'y', }); - assertEquals(expected, channel.readOutbound()); + + CompositeByteBuf actual = Unpooled.compositeBuffer(); + for (;;) { + ByteBuf m = (ByteBuf) channel.readOutbound(); + if (m == null) { + break; + } + actual.addComponent(m); + actual.writerIndex(actual.writerIndex() + m.readableBytes()); + } + assertEquals(expected, actual); in.release(); } diff --git a/codec/src/test/java/io/netty/handler/codec/compression/SnappyIntegrationTest.java b/codec/src/test/java/io/netty/handler/codec/compression/SnappyIntegrationTest.java index f92b83c6a5..a073ec9945 100644 --- a/codec/src/test/java/io/netty/handler/codec/compression/SnappyIntegrationTest.java +++ b/codec/src/test/java/io/netty/handler/codec/compression/SnappyIntegrationTest.java @@ -16,7 +16,9 @@ package io.netty.handler.codec.compression; import io.netty.buffer.ByteBuf; -import io.netty.channel.embedded.EmbeddedByteChannel; +import io.netty.buffer.CompositeByteBuf; +import io.netty.buffer.Unpooled; +import io.netty.channel.embedded.EmbeddedChannel; import io.netty.util.CharsetUtil; import org.junit.Test; @@ -116,17 +118,25 @@ public class SnappyIntegrationTest { } private static void testIdentity(ByteBuf in) { - EmbeddedByteChannel encoder = new EmbeddedByteChannel(new SnappyFramedEncoder()); - EmbeddedByteChannel decoder = new EmbeddedByteChannel(new SnappyFramedDecoder()); + EmbeddedChannel encoder = new EmbeddedChannel(new SnappyFramedEncoder()); + EmbeddedChannel decoder = new EmbeddedChannel(new SnappyFramedDecoder()); try { encoder.writeOutbound(in.copy()); - ByteBuf compressed = encoder.readOutbound(); + ByteBuf compressed = (ByteBuf) encoder.readOutbound(); assertThat(compressed, is(notNullValue())); assertThat(compressed, is(not(in))); - decoder.writeInbound(compressed); + decoder.writeInbound(compressed.retain()); assertFalse(compressed.isReadable()); - compressed.discardReadBytes(); - ByteBuf decompressed = (ByteBuf) decoder.readInbound(); + compressed.release(); + CompositeByteBuf decompressed = Unpooled.compositeBuffer(); + for (;;) { + Object o = decoder.readInbound(); + if (o == null) { + break; + } + decompressed.addComponent((ByteBuf) o); + decompressed.writerIndex(decompressed.writerIndex() + ((ByteBuf) o).readableBytes()); + } assertEquals(in, decompressed); } finally { // Avoids memory leak through AbstractChannel.allChannels diff --git a/codec/src/test/java/io/netty/handler/codec/compression/SnappyTest.java b/codec/src/test/java/io/netty/handler/codec/compression/SnappyTest.java index 5fcc03ea60..c7122d1913 100644 --- a/codec/src/test/java/io/netty/handler/codec/compression/SnappyTest.java +++ b/codec/src/test/java/io/netty/handler/codec/compression/SnappyTest.java @@ -67,7 +67,7 @@ public class SnappyTest { assertEquals("Copy was not decoded correctly", expected, out); } - @Test(expected = CompressionException.class) + @Test(expected = DecompressionException.class) public void testDecodeCopyWithTinyOffset() throws Exception { ByteBuf in = Unpooled.wrappedBuffer(new byte[] { 0x0b, // preamble length @@ -80,7 +80,7 @@ public class SnappyTest { snappy.decode(in, out); } - @Test(expected = CompressionException.class) + @Test(expected = DecompressionException.class) public void testDecodeCopyWithOffsetBeforeChunk() throws Exception { ByteBuf in = Unpooled.wrappedBuffer(new byte[] { 0x0a, // preamble length @@ -93,7 +93,7 @@ public class SnappyTest { snappy.decode(in, out); } - @Test(expected = CompressionException.class) + @Test(expected = DecompressionException.class) public void testDecodeWithOverlyLongPreamble() throws Exception { ByteBuf in = Unpooled.wrappedBuffer(new byte[] { -0x80, -0x80, -0x80, -0x80, 0x7f, // preamble length @@ -187,7 +187,7 @@ public class SnappyTest { validateChecksum(maskChecksum(0x37c55159), input); } - @Test(expected = CompressionException.class) + @Test(expected = DecompressionException.class) public void testValidateChecksumFails() { ByteBuf input = Unpooled.wrappedBuffer(new byte[] { 'y', 't', 't', 'e', 'n' diff --git a/codec/src/test/java/io/netty/handler/codec/frame/DelimiterBasedFrameDecoderTest.java b/codec/src/test/java/io/netty/handler/codec/frame/DelimiterBasedFrameDecoderTest.java index f9f7e5388a..77f7fa0232 100644 --- a/codec/src/test/java/io/netty/handler/codec/frame/DelimiterBasedFrameDecoderTest.java +++ b/codec/src/test/java/io/netty/handler/codec/frame/DelimiterBasedFrameDecoderTest.java @@ -15,23 +15,23 @@ */ package io.netty.handler.codec.frame; -import static org.junit.Assert.*; import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; -import io.netty.channel.embedded.EmbeddedByteChannel; +import io.netty.channel.embedded.EmbeddedChannel; import io.netty.handler.codec.DecoderException; import io.netty.handler.codec.DelimiterBasedFrameDecoder; import io.netty.handler.codec.Delimiters; import io.netty.handler.codec.TooLongFrameException; import io.netty.util.CharsetUtil; - import org.junit.Test; +import static org.junit.Assert.*; + public class DelimiterBasedFrameDecoderTest { @Test public void testFailSlowTooLongFrameRecovery() throws Exception { - EmbeddedByteChannel ch = new EmbeddedByteChannel( + EmbeddedChannel ch = new EmbeddedChannel( new DelimiterBasedFrameDecoder(1, true, false, Delimiters.nulDelimiter())); for (int i = 0; i < 2; i ++) { @@ -51,7 +51,7 @@ public class DelimiterBasedFrameDecoderTest { @Test public void testFailFastTooLongFrameRecovery() throws Exception { - EmbeddedByteChannel ch = new EmbeddedByteChannel( + EmbeddedChannel ch = new EmbeddedChannel( new DelimiterBasedFrameDecoder(1, Delimiters.nulDelimiter())); for (int i = 0; i < 2; i ++) { diff --git a/codec/src/test/java/io/netty/handler/codec/frame/LengthFieldBasedFrameDecoderTest.java b/codec/src/test/java/io/netty/handler/codec/frame/LengthFieldBasedFrameDecoderTest.java index 80ceb6a009..401eed24f9 100644 --- a/codec/src/test/java/io/netty/handler/codec/frame/LengthFieldBasedFrameDecoderTest.java +++ b/codec/src/test/java/io/netty/handler/codec/frame/LengthFieldBasedFrameDecoderTest.java @@ -15,21 +15,21 @@ */ package io.netty.handler.codec.frame; -import static org.junit.Assert.*; import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; -import io.netty.channel.embedded.EmbeddedByteChannel; +import io.netty.channel.embedded.EmbeddedChannel; import io.netty.handler.codec.DecoderException; import io.netty.handler.codec.LengthFieldBasedFrameDecoder; import io.netty.handler.codec.TooLongFrameException; import io.netty.util.CharsetUtil; - import org.junit.Test; +import static org.junit.Assert.*; + public class LengthFieldBasedFrameDecoderTest { @Test public void testFailSlowTooLongFrameRecovery() throws Exception { - EmbeddedByteChannel ch = new EmbeddedByteChannel( + EmbeddedChannel ch = new EmbeddedChannel( new LengthFieldBasedFrameDecoder(5, 0, 4, 0, 4, false)); for (int i = 0; i < 2; i ++) { @@ -49,7 +49,7 @@ public class LengthFieldBasedFrameDecoderTest { @Test public void testFailFastTooLongFrameRecovery() throws Exception { - EmbeddedByteChannel ch = new EmbeddedByteChannel( + EmbeddedChannel ch = new EmbeddedChannel( new LengthFieldBasedFrameDecoder(5, 0, 4, 0, 4)); for (int i = 0; i < 2; i ++) { diff --git a/codec/src/test/java/io/netty/handler/codec/frame/LengthFieldPrependerTest.java b/codec/src/test/java/io/netty/handler/codec/frame/LengthFieldPrependerTest.java index 16bfa998ab..266034fdb8 100644 --- a/codec/src/test/java/io/netty/handler/codec/frame/LengthFieldPrependerTest.java +++ b/codec/src/test/java/io/netty/handler/codec/frame/LengthFieldPrependerTest.java @@ -17,7 +17,8 @@ package io.netty.handler.codec.frame; import io.netty.buffer.ByteBuf; import io.netty.channel.IncompleteFlushException; -import io.netty.channel.embedded.EmbeddedByteChannel; +import io.netty.channel.embedded.EmbeddedChannel; +import io.netty.handler.codec.EncoderException; import io.netty.handler.codec.LengthFieldPrepender; import io.netty.util.CharsetUtil; import org.junit.Before; @@ -38,32 +39,32 @@ public class LengthFieldPrependerTest { @Test public void testPrependLength() throws Exception { - final EmbeddedByteChannel ch = new EmbeddedByteChannel(new LengthFieldPrepender(4)); + final EmbeddedChannel ch = new EmbeddedChannel(new LengthFieldPrepender(4)); ch.writeOutbound(msg); - assertThat(ch.readOutbound(), is(wrappedBuffer(new byte[]{0, 0, 0, 1, 'A'}))); + assertThat((ByteBuf) ch.readOutbound(), is(wrappedBuffer(new byte[]{0, 0, 0, 1, 'A'}))); } @Test public void testPrependLengthIncludesLengthFieldLength() throws Exception { - final EmbeddedByteChannel ch = new EmbeddedByteChannel(new LengthFieldPrepender(4, true)); + final EmbeddedChannel ch = new EmbeddedChannel(new LengthFieldPrepender(4, true)); ch.writeOutbound(msg); - assertThat(ch.readOutbound(), is(wrappedBuffer(new byte[]{0, 0, 0, 5, 'A'}))); + assertThat((ByteBuf) ch.readOutbound(), is(wrappedBuffer(new byte[]{0, 0, 0, 5, 'A'}))); } @Test public void testPrependAdjustedLength() throws Exception { - final EmbeddedByteChannel ch = new EmbeddedByteChannel(new LengthFieldPrepender(4, -1)); + final EmbeddedChannel ch = new EmbeddedChannel(new LengthFieldPrepender(4, -1)); ch.writeOutbound(msg); - assertThat(ch.readOutbound(), is(wrappedBuffer(new byte[]{0, 0, 0, 0, 'A'}))); + assertThat((ByteBuf) ch.readOutbound(), is(wrappedBuffer(new byte[]{0, 0, 0, 0, 'A'}))); } @Test public void testAdjustedLengthLessThanZero() throws Exception { - final EmbeddedByteChannel ch = new EmbeddedByteChannel(new LengthFieldPrepender(4, -2)); + final EmbeddedChannel ch = new EmbeddedChannel(new LengthFieldPrepender(4, -2)); try { ch.writeOutbound(msg); - fail(IncompleteFlushException.class.getSimpleName() + " must be raised."); - } catch (IncompleteFlushException e) { + fail(EncoderException.class.getSimpleName() + " must be raised."); + } catch (EncoderException e) { // Expected } } diff --git a/codec/src/test/java/io/netty/handler/codec/marshalling/AbstractCompatibleMarshallingDecoderTest.java b/codec/src/test/java/io/netty/handler/codec/marshalling/AbstractCompatibleMarshallingDecoderTest.java index 3be464deff..1b65d5fbb0 100644 --- a/codec/src/test/java/io/netty/handler/codec/marshalling/AbstractCompatibleMarshallingDecoderTest.java +++ b/codec/src/test/java/io/netty/handler/codec/marshalling/AbstractCompatibleMarshallingDecoderTest.java @@ -18,7 +18,7 @@ package io.netty.handler.codec.marshalling; import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import io.netty.channel.ChannelHandler; -import io.netty.channel.embedded.EmbeddedByteChannel; +import io.netty.channel.embedded.EmbeddedChannel; import org.jboss.marshalling.Marshaller; import org.jboss.marshalling.MarshallerFactory; import org.jboss.marshalling.Marshalling; @@ -39,7 +39,7 @@ public abstract class AbstractCompatibleMarshallingDecoderTest { MarshallerFactory marshallerFactory = createMarshallerFactory(); MarshallingConfiguration configuration = createMarshallingConfig(); - EmbeddedByteChannel ch = new EmbeddedByteChannel(createDecoder(Integer.MAX_VALUE)); + EmbeddedChannel ch = new EmbeddedChannel(createDecoder(Integer.MAX_VALUE)); ByteArrayOutputStream bout = new ByteArrayOutputStream(); Marshaller marshaller = marshallerFactory.createMarshaller(configuration); @@ -69,7 +69,7 @@ public abstract class AbstractCompatibleMarshallingDecoderTest { MarshallerFactory marshallerFactory = createMarshallerFactory(); MarshallingConfiguration configuration = createMarshallingConfig(); - EmbeddedByteChannel ch = new EmbeddedByteChannel(createDecoder(Integer.MAX_VALUE)); + EmbeddedChannel ch = new EmbeddedChannel(createDecoder(Integer.MAX_VALUE)); ByteArrayOutputStream bout = new ByteArrayOutputStream(); Marshaller marshaller = marshallerFactory.createMarshaller(configuration); @@ -83,7 +83,7 @@ public abstract class AbstractCompatibleMarshallingDecoderTest { ByteBuf buffer = input(testBytes); ByteBuf slice = buffer.readSlice(2); - ch.writeInbound(slice); + ch.writeInbound(slice.retain()); ch.writeInbound(buffer); assertTrue(ch.finish()); @@ -100,7 +100,7 @@ public abstract class AbstractCompatibleMarshallingDecoderTest { MarshallingConfiguration configuration = createMarshallingConfig(); ChannelHandler mDecoder = createDecoder(4); - EmbeddedByteChannel ch = new EmbeddedByteChannel(mDecoder); + EmbeddedChannel ch = new EmbeddedChannel(mDecoder); ByteArrayOutputStream bout = new ByteArrayOutputStream(); Marshaller marshaller = marshallerFactory.createMarshaller(configuration); @@ -113,7 +113,7 @@ public abstract class AbstractCompatibleMarshallingDecoderTest { onTooBigFrame(ch, input(testBytes)); } - protected void onTooBigFrame(EmbeddedByteChannel ch, ByteBuf input) { + protected void onTooBigFrame(EmbeddedChannel ch, ByteBuf input) { ch.writeInbound(input); assertFalse(ch.isActive()); } diff --git a/codec/src/test/java/io/netty/handler/codec/marshalling/AbstractCompatibleMarshallingEncoderTest.java b/codec/src/test/java/io/netty/handler/codec/marshalling/AbstractCompatibleMarshallingEncoderTest.java index dc520738e6..2a03e827cb 100644 --- a/codec/src/test/java/io/netty/handler/codec/marshalling/AbstractCompatibleMarshallingEncoderTest.java +++ b/codec/src/test/java/io/netty/handler/codec/marshalling/AbstractCompatibleMarshallingEncoderTest.java @@ -17,7 +17,7 @@ package io.netty.handler.codec.marshalling; import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandler; -import io.netty.channel.embedded.EmbeddedByteChannel; +import io.netty.channel.embedded.EmbeddedChannel; import org.jboss.marshalling.MarshallerFactory; import org.jboss.marshalling.Marshalling; import org.jboss.marshalling.MarshallingConfiguration; @@ -38,12 +38,12 @@ public abstract class AbstractCompatibleMarshallingEncoderTest { final MarshallerFactory marshallerFactory = createMarshallerFactory(); final MarshallingConfiguration configuration = createMarshallingConfig(); - EmbeddedByteChannel ch = new EmbeddedByteChannel(createEncoder()); + EmbeddedChannel ch = new EmbeddedChannel(createEncoder()); ch.writeOutbound(testObject); assertTrue(ch.finish()); - ByteBuf buffer = ch.readOutbound(); + ByteBuf buffer = (ByteBuf) ch.readOutbound(); Unmarshaller unmarshaller = marshallerFactory.createUnmarshaller(configuration); unmarshaller.start(Marshalling.createByteInput(truncate(buffer).nioBuffer())); diff --git a/codec/src/test/java/io/netty/handler/codec/marshalling/RiverMarshallingDecoderTest.java b/codec/src/test/java/io/netty/handler/codec/marshalling/RiverMarshallingDecoderTest.java index 17d7cb2d59..b68e89a43c 100644 --- a/codec/src/test/java/io/netty/handler/codec/marshalling/RiverMarshallingDecoderTest.java +++ b/codec/src/test/java/io/netty/handler/codec/marshalling/RiverMarshallingDecoderTest.java @@ -18,7 +18,7 @@ package io.netty.handler.codec.marshalling; import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import io.netty.channel.ChannelHandler; -import io.netty.channel.embedded.EmbeddedByteChannel; +import io.netty.channel.embedded.EmbeddedChannel; import io.netty.handler.codec.CodecException; import io.netty.handler.codec.TooLongFrameException; @@ -40,7 +40,7 @@ public class RiverMarshallingDecoderTest extends RiverCompatibleMarshallingDecod } @Override - protected void onTooBigFrame(EmbeddedByteChannel ch, ByteBuf input) { + protected void onTooBigFrame(EmbeddedChannel ch, ByteBuf input) { try { ch.writeInbound(input); fail(); diff --git a/codec/src/test/java/io/netty/handler/codec/marshalling/SerialMarshallingDecoderTest.java b/codec/src/test/java/io/netty/handler/codec/marshalling/SerialMarshallingDecoderTest.java index 6f27baf078..b86dcfffe1 100644 --- a/codec/src/test/java/io/netty/handler/codec/marshalling/SerialMarshallingDecoderTest.java +++ b/codec/src/test/java/io/netty/handler/codec/marshalling/SerialMarshallingDecoderTest.java @@ -18,7 +18,7 @@ package io.netty.handler.codec.marshalling; import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import io.netty.channel.ChannelHandler; -import io.netty.channel.embedded.EmbeddedByteChannel; +import io.netty.channel.embedded.EmbeddedChannel; import io.netty.handler.codec.CodecException; import io.netty.handler.codec.TooLongFrameException; @@ -40,7 +40,7 @@ public class SerialMarshallingDecoderTest extends SerialCompatibleMarshallingDec } @Override - protected void onTooBigFrame(EmbeddedByteChannel ch, ByteBuf input) { + protected void onTooBigFrame(EmbeddedChannel ch, ByteBuf input) { try { ch.writeInbound(input); fail(); diff --git a/codec/src/test/java/io/netty/handler/codec/protobuf/ProtobufVarint32FrameDecoderTest.java b/codec/src/test/java/io/netty/handler/codec/protobuf/ProtobufVarint32FrameDecoderTest.java index 65ebf5956a..00cd74ad1c 100644 --- a/codec/src/test/java/io/netty/handler/codec/protobuf/ProtobufVarint32FrameDecoderTest.java +++ b/codec/src/test/java/io/netty/handler/codec/protobuf/ProtobufVarint32FrameDecoderTest.java @@ -15,23 +15,23 @@ */ package io.netty.handler.codec.protobuf; +import io.netty.buffer.ByteBuf; +import io.netty.channel.embedded.EmbeddedChannel; +import org.junit.Before; +import org.junit.Test; + import static io.netty.buffer.Unpooled.*; import static org.hamcrest.core.Is.*; import static org.hamcrest.core.IsNull.*; import static org.junit.Assert.*; -import io.netty.buffer.ByteBuf; -import io.netty.channel.embedded.EmbeddedByteChannel; - -import org.junit.Before; -import org.junit.Test; public class ProtobufVarint32FrameDecoderTest { - private EmbeddedByteChannel ch; + private EmbeddedChannel ch; @Before public void setUp() { - ch = new EmbeddedByteChannel(new ProtobufVarint32FrameDecoder()); + ch = new EmbeddedChannel(new ProtobufVarint32FrameDecoder()); } @Test diff --git a/codec/src/test/java/io/netty/handler/codec/protobuf/ProtobufVarint32LengthFieldPrependerTest.java b/codec/src/test/java/io/netty/handler/codec/protobuf/ProtobufVarint32LengthFieldPrependerTest.java index 681a13f11b..7b946f4148 100644 --- a/codec/src/test/java/io/netty/handler/codec/protobuf/ProtobufVarint32LengthFieldPrependerTest.java +++ b/codec/src/test/java/io/netty/handler/codec/protobuf/ProtobufVarint32LengthFieldPrependerTest.java @@ -15,28 +15,29 @@ */ package io.netty.handler.codec.protobuf; -import static io.netty.buffer.Unpooled.*; -import static org.hamcrest.core.Is.*; -import static org.junit.Assert.*; -import io.netty.channel.embedded.EmbeddedByteChannel; - +import io.netty.buffer.ByteBuf; +import io.netty.channel.embedded.EmbeddedChannel; import org.junit.Before; import org.junit.Test; +import static io.netty.buffer.Unpooled.*; +import static org.hamcrest.core.Is.*; +import static org.junit.Assert.*; + public class ProtobufVarint32LengthFieldPrependerTest { - private EmbeddedByteChannel ch; + private EmbeddedChannel ch; @Before public void setUp() { - ch = new EmbeddedByteChannel(new ProtobufVarint32LengthFieldPrepender()); + ch = new EmbeddedChannel(new ProtobufVarint32LengthFieldPrepender()); } @Test public void testTinyEncode() { byte[] b = { 4, 1, 1, 1, 1 }; ch.writeOutbound(wrappedBuffer(b, 1, b.length - 1)); - assertThat(ch.readOutbound(), is(wrappedBuffer(b))); + assertThat((ByteBuf) ch.readOutbound(), is(wrappedBuffer(b))); } @Test @@ -48,6 +49,6 @@ public class ProtobufVarint32LengthFieldPrependerTest { b[0] = -2; b[1] = 15; ch.writeOutbound(wrappedBuffer(b, 2, b.length - 2)); - assertThat(ch.readOutbound(), is(wrappedBuffer(b))); + assertThat((ByteBuf) ch.readOutbound(), is(wrappedBuffer(b))); } } diff --git a/common/pom.xml b/common/pom.xml index a0bc558816..438222a815 100644 --- a/common/pom.xml +++ b/common/pom.xml @@ -21,7 +21,7 @@ io.netty netty-parent - 4.0.0.Final-SNAPSHOT + 4.0.0.CR4-SNAPSHOT netty-common diff --git a/common/src/main/java/io/netty/util/Recycler.java b/common/src/main/java/io/netty/util/Recycler.java new file mode 100644 index 0000000000..4d14285137 --- /dev/null +++ b/common/src/main/java/io/netty/util/Recycler.java @@ -0,0 +1,90 @@ +/* + * Copyright 2013 The Netty Project + * + * The Netty Project licenses this file to you under the Apache License, + * version 2.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ + +package io.netty.util; + +import java.util.ArrayDeque; +import java.util.Deque; +import java.util.IdentityHashMap; +import java.util.Map; + +/** + * Light-weight object pool based on a thread-local stack. + * + * @param the type of the pooled object + */ +public abstract class Recycler { + + private final ThreadLocal> threadLocal = new ThreadLocal>() { + @Override + protected Stack initialValue() { + return new Stack(Recycler.this, Thread.currentThread()); + } + }; + + public final T get() { + Stack stack = threadLocal.get(); + T o = stack.pop(); + if (o == null) { + o = newObject(stack); + } + return o; + } + + public final boolean recycle(T o, Handle handle) { + @SuppressWarnings("unchecked") + Stack stack = (Stack) handle; + if (stack.parent != this) { + return false; + } + + if (Thread.currentThread() != stack.thread) { + return false; + } + + stack.push(o); + return true; + } + + protected abstract T newObject(Handle handle); + + public interface Handle { } + + static final class Stack implements Handle { + final Recycler parent; + final Thread thread; + private final Deque deque = new ArrayDeque(); + private final Map map = new IdentityHashMap(); + + Stack(Recycler parent, Thread thread) { + this.parent = parent; + this.thread = thread; + } + + T pop() { + T ret = deque.pollLast(); + map.remove(ret); + return ret; + } + + void push(T o) { + if (map.put(o, Boolean.TRUE) != null) { + throw new IllegalStateException("recycled already"); + } + deque.addLast(o); + } + } +} diff --git a/common/src/main/java/io/netty/util/ResourceLeakDetector.java b/common/src/main/java/io/netty/util/ResourceLeakDetector.java index 26d45785e1..a6ea748718 100644 --- a/common/src/main/java/io/netty/util/ResourceLeakDetector.java +++ b/common/src/main/java/io/netty/util/ResourceLeakDetector.java @@ -28,12 +28,12 @@ import java.util.concurrent.atomic.AtomicBoolean; public final class ResourceLeakDetector { - private static final boolean ENABLED = SystemPropertyUtil.getBoolean("io.netty.resourceLeakDetection", false); + private static final boolean DISABLED = SystemPropertyUtil.getBoolean("io.netty.noResourceLeakDetection", false); private static final InternalLogger logger = InternalLoggerFactory.getInstance(ResourceLeakDetector.class); static { - logger.debug("io.netty.resourceLeakDetection: {}", ENABLED); + logger.debug("io.netty.noResourceLeakDetection: {}", DISABLED); } private static final int DEFAULT_SAMPLING_INTERVAL = 113; @@ -92,7 +92,7 @@ public final class ResourceLeakDetector { } public ResourceLeak open(T obj) { - if (!ENABLED || leakCheckCnt ++ % samplingInterval != 0) { + if (DISABLED || leakCheckCnt ++ % samplingInterval != 0) { return NOOP; } diff --git a/example/pom.xml b/example/pom.xml index 410d2b71ba..26597f79df 100644 --- a/example/pom.xml +++ b/example/pom.xml @@ -21,7 +21,7 @@ io.netty netty-parent - 4.0.0.Final-SNAPSHOT + 4.0.0.CR4-SNAPSHOT netty-example diff --git a/example/src/main/java/io/netty/example/applet/AppletDiscardServer.java b/example/src/main/java/io/netty/example/applet/AppletDiscardServer.java index e86e7adf53..878b14fb37 100644 --- a/example/src/main/java/io/netty/example/applet/AppletDiscardServer.java +++ b/example/src/main/java/io/netty/example/applet/AppletDiscardServer.java @@ -19,9 +19,10 @@ import io.netty.bootstrap.ServerBootstrap; import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.ChannelInboundByteHandlerAdapter; +import io.netty.channel.ChannelInboundHandlerAdapter; import io.netty.channel.ChannelInitializer; import io.netty.channel.EventLoopGroup; +import io.netty.channel.MessageList; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.SocketChannel; import io.netty.channel.socket.nio.NioServerSocketChannel; @@ -72,12 +73,15 @@ public class AppletDiscardServer extends JApplet { } } - private static final class DiscardServerHandler extends ChannelInboundByteHandlerAdapter { + private static final class DiscardServerHandler extends ChannelInboundHandlerAdapter { @Override - public void inboundBufferUpdated(ChannelHandlerContext ctx, ByteBuf in) throws Exception { - System.out.println("Received: " + in.toString(CharsetUtil.UTF_8)); - in.clear(); + public void messageReceived(ChannelHandlerContext ctx, MessageList msgs) throws Exception { + MessageList bufs = msgs.cast(); + for (int i = 0; i < bufs.size(); i++) { + System.out.println("Received: " + bufs.get(i).toString(CharsetUtil.UTF_8)); + } + msgs.releaseAllAndRecycle(); } @Override diff --git a/example/src/main/java/io/netty/example/discard/DiscardClientHandler.java b/example/src/main/java/io/netty/example/discard/DiscardClientHandler.java index 22d1be1318..c28c57fb6e 100644 --- a/example/src/main/java/io/netty/example/discard/DiscardClientHandler.java +++ b/example/src/main/java/io/netty/example/discard/DiscardClientHandler.java @@ -19,7 +19,8 @@ import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelFutureListener; import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.ChannelInboundByteHandlerAdapter; +import io.netty.channel.ChannelInboundHandlerAdapter; +import io.netty.channel.MessageList; import java.util.logging.Level; import java.util.logging.Logger; @@ -27,7 +28,7 @@ import java.util.logging.Logger; /** * Handles a client-side channel. */ -public class DiscardClientHandler extends ChannelInboundByteHandlerAdapter { +public class DiscardClientHandler extends ChannelInboundHandlerAdapter { private static final Logger logger = Logger.getLogger( DiscardClientHandler.class.getName()); @@ -57,10 +58,14 @@ public class DiscardClientHandler extends ChannelInboundByteHandlerAdapter { } @Override - public void inboundBufferUpdated(ChannelHandlerContext ctx, ByteBuf in) - throws Exception { + public void channelInactive(ChannelHandlerContext ctx) throws Exception { + content.release(); + } + + @Override + public void messageReceived(ChannelHandlerContext ctx, MessageList msgs) throws Exception { // Server is supposed to send nothing, but if it sends something, discard it. - in.clear(); + msgs.releaseAllAndRecycle(); } @Override @@ -77,15 +82,9 @@ public class DiscardClientHandler extends ChannelInboundByteHandlerAdapter { long counter; private void generateTraffic() { - // Fill the outbound buffer up to 64KiB - ByteBuf out = ctx.nextOutboundByteBuffer(); - while (out.readableBytes() < 65536) { - out.writeBytes(content, 0, content.readableBytes()); - } - // Flush the outbound buffer to the socket. // Once flushed, generate the same amount of traffic again. - ctx.flush().addListener(trafficGenerator); + ctx.write(content.duplicate().retain()).addListener(trafficGenerator); } private final ChannelFutureListener trafficGenerator = new ChannelFutureListener() { diff --git a/example/src/main/java/io/netty/example/discard/DiscardServerHandler.java b/example/src/main/java/io/netty/example/discard/DiscardServerHandler.java index 8e43955d0d..e2386fd2d0 100644 --- a/example/src/main/java/io/netty/example/discard/DiscardServerHandler.java +++ b/example/src/main/java/io/netty/example/discard/DiscardServerHandler.java @@ -15,9 +15,9 @@ */ package io.netty.example.discard; -import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.ChannelInboundByteHandlerAdapter; +import io.netty.channel.ChannelInboundHandlerAdapter; +import io.netty.channel.MessageList; import java.util.logging.Level; import java.util.logging.Logger; @@ -25,16 +25,15 @@ import java.util.logging.Logger; /** * Handles a server-side channel. */ -public class DiscardServerHandler extends ChannelInboundByteHandlerAdapter { +public class DiscardServerHandler extends ChannelInboundHandlerAdapter { private static final Logger logger = Logger.getLogger( DiscardServerHandler.class.getName()); @Override - public void inboundBufferUpdated(ChannelHandlerContext ctx, ByteBuf in) - throws Exception { + public void messageReceived(ChannelHandlerContext ctx, MessageList msgs) throws Exception { // Discard the received data silently. - in.clear(); + msgs.releaseAllAndRecycle(); } @Override diff --git a/example/src/main/java/io/netty/example/echo/EchoClient.java b/example/src/main/java/io/netty/example/echo/EchoClient.java index d124ac2899..15eafffab9 100644 --- a/example/src/main/java/io/netty/example/echo/EchoClient.java +++ b/example/src/main/java/io/netty/example/echo/EchoClient.java @@ -23,8 +23,6 @@ import io.netty.channel.EventLoopGroup; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.SocketChannel; import io.netty.channel.socket.nio.NioSocketChannel; -import io.netty.handler.logging.LogLevel; -import io.netty.handler.logging.LoggingHandler; /** * Sends one message when a connection is open and echoes back any received @@ -56,7 +54,7 @@ public class EchoClient { @Override public void initChannel(SocketChannel ch) throws Exception { ch.pipeline().addLast( - new LoggingHandler(LogLevel.INFO), + //new LoggingHandler(LogLevel.INFO), new EchoClientHandler(firstMessageSize)); } }); diff --git a/example/src/main/java/io/netty/example/echo/EchoClientHandler.java b/example/src/main/java/io/netty/example/echo/EchoClientHandler.java index ad52c616dd..fd56fce11e 100644 --- a/example/src/main/java/io/netty/example/echo/EchoClientHandler.java +++ b/example/src/main/java/io/netty/example/echo/EchoClientHandler.java @@ -18,7 +18,8 @@ package io.netty.example.echo; import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.ChannelInboundByteHandlerAdapter; +import io.netty.channel.ChannelInboundHandlerAdapter; +import io.netty.channel.MessageList; import java.util.logging.Level; import java.util.logging.Logger; @@ -28,7 +29,7 @@ import java.util.logging.Logger; * traffic between the echo client and server by sending the first message to * the server. */ -public class EchoClientHandler extends ChannelInboundByteHandlerAdapter { +public class EchoClientHandler extends ChannelInboundHandlerAdapter { private static final Logger logger = Logger.getLogger( EchoClientHandler.class.getName()); @@ -54,10 +55,8 @@ public class EchoClientHandler extends ChannelInboundByteHandlerAdapter { } @Override - public void inboundBufferUpdated(ChannelHandlerContext ctx, ByteBuf in) { - ByteBuf out = ctx.nextOutboundByteBuffer(); - out.writeBytes(in); - ctx.flush(); + public void messageReceived(ChannelHandlerContext ctx, MessageList msgs) throws Exception { + ctx.write(msgs); } @Override diff --git a/example/src/main/java/io/netty/example/echo/EchoServer.java b/example/src/main/java/io/netty/example/echo/EchoServer.java index ac6f14398b..55d8d6b48a 100644 --- a/example/src/main/java/io/netty/example/echo/EchoServer.java +++ b/example/src/main/java/io/netty/example/echo/EchoServer.java @@ -51,7 +51,7 @@ public class EchoServer { @Override public void initChannel(SocketChannel ch) throws Exception { ch.pipeline().addLast( - new LoggingHandler(LogLevel.INFO), + //new LoggingHandler(LogLevel.INFO), new EchoServerHandler()); } }); diff --git a/example/src/main/java/io/netty/example/echo/EchoServerHandler.java b/example/src/main/java/io/netty/example/echo/EchoServerHandler.java index 4d050b073e..110af40f70 100644 --- a/example/src/main/java/io/netty/example/echo/EchoServerHandler.java +++ b/example/src/main/java/io/netty/example/echo/EchoServerHandler.java @@ -15,10 +15,10 @@ */ package io.netty.example.echo; -import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandler.Sharable; import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.ChannelInboundByteHandlerAdapter; +import io.netty.channel.ChannelInboundHandlerAdapter; +import io.netty.channel.MessageList; import java.util.logging.Level; import java.util.logging.Logger; @@ -27,16 +27,14 @@ import java.util.logging.Logger; * Handler implementation for the echo server. */ @Sharable -public class EchoServerHandler extends ChannelInboundByteHandlerAdapter { +public class EchoServerHandler extends ChannelInboundHandlerAdapter { private static final Logger logger = Logger.getLogger( EchoServerHandler.class.getName()); @Override - public void inboundBufferUpdated(ChannelHandlerContext ctx, ByteBuf in) { - ByteBuf out = ctx.nextOutboundByteBuffer(); - out.writeBytes(in); - ctx.flush(); + public void messageReceived(ChannelHandlerContext ctx, MessageList msgs) throws Exception { + ctx.write(msgs); } @Override diff --git a/example/src/main/java/io/netty/example/factorial/BigIntegerDecoder.java b/example/src/main/java/io/netty/example/factorial/BigIntegerDecoder.java index 459e842b32..8ed01fa4f0 100644 --- a/example/src/main/java/io/netty/example/factorial/BigIntegerDecoder.java +++ b/example/src/main/java/io/netty/example/factorial/BigIntegerDecoder.java @@ -16,8 +16,8 @@ package io.netty.example.factorial; import io.netty.buffer.ByteBuf; -import io.netty.buffer.MessageBuf; import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.MessageList; import io.netty.handler.codec.ByteToMessageDecoder; import io.netty.handler.codec.CorruptedFrameException; @@ -32,7 +32,7 @@ import java.math.BigInteger; public class BigIntegerDecoder extends ByteToMessageDecoder { @Override - protected void decode(ChannelHandlerContext ctx, ByteBuf in, MessageBuf out) { + protected void decode(ChannelHandlerContext ctx, ByteBuf in, MessageList out) { // Wait until the length prefix is available. if (in.readableBytes() < 5) { return; diff --git a/example/src/main/java/io/netty/example/factorial/FactorialClientHandler.java b/example/src/main/java/io/netty/example/factorial/FactorialClientHandler.java index 6821590b84..28fd76e80f 100644 --- a/example/src/main/java/io/netty/example/factorial/FactorialClientHandler.java +++ b/example/src/main/java/io/netty/example/factorial/FactorialClientHandler.java @@ -15,11 +15,11 @@ */ package io.netty.example.factorial; -import io.netty.buffer.MessageBuf; import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelFutureListener; import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.ChannelInboundMessageHandlerAdapter; +import io.netty.channel.MessageList; +import io.netty.channel.SimpleChannelInboundHandler; import java.math.BigInteger; import java.util.concurrent.BlockingQueue; @@ -34,7 +34,7 @@ import java.util.logging.Logger; * to create a new handler instance whenever you create a new channel and insert * this handler to avoid a race condition. */ -public class FactorialClientHandler extends ChannelInboundMessageHandlerAdapter { +public class FactorialClientHandler extends SimpleChannelInboundHandler { private static final Logger logger = Logger.getLogger( FactorialClientHandler.class.getName()); @@ -98,7 +98,7 @@ public class FactorialClientHandler extends ChannelInboundMessageHandlerAdapter< private void sendNumbers() { // Do not send more than 4096 numbers. boolean finished = false; - MessageBuf out = ctx.nextOutboundMessageBuffer(); + MessageList out = MessageList.newInstance(4096); while (out.size() < 4096) { if (i <= count) { out.add(Integer.valueOf(i)); @@ -109,7 +109,7 @@ public class FactorialClientHandler extends ChannelInboundMessageHandlerAdapter< } } - ChannelFuture f = ctx.flush(); + ChannelFuture f = ctx.write(out); if (!finished) { f.addListener(numberSender); } diff --git a/example/src/main/java/io/netty/example/factorial/FactorialServerHandler.java b/example/src/main/java/io/netty/example/factorial/FactorialServerHandler.java index 3cc4592680..a21b765bfa 100644 --- a/example/src/main/java/io/netty/example/factorial/FactorialServerHandler.java +++ b/example/src/main/java/io/netty/example/factorial/FactorialServerHandler.java @@ -16,7 +16,8 @@ package io.netty.example.factorial; import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.ChannelInboundMessageHandlerAdapter; +import io.netty.channel.ChannelInboundHandlerAdapter; +import io.netty.channel.MessageList; import java.math.BigInteger; import java.util.Formatter; @@ -30,7 +31,7 @@ import java.util.logging.Logger; * to create a new handler instance whenever you create a new channel and insert * this handler to avoid a race condition. */ -public class FactorialServerHandler extends ChannelInboundMessageHandlerAdapter { +public class FactorialServerHandler extends ChannelInboundHandlerAdapter { private static final Logger logger = Logger.getLogger( FactorialServerHandler.class.getName()); @@ -40,11 +41,16 @@ public class FactorialServerHandler extends ChannelInboundMessageHandlerAdapter< @Override public void messageReceived( - ChannelHandlerContext ctx, BigInteger msg) throws Exception { - // Calculate the cumulative factorial and send it to the client. - lastMultiplier = msg; - factorial = factorial.multiply(msg); - ctx.write(factorial); + ChannelHandlerContext ctx, MessageList msgs) throws Exception { + MessageList ints = msgs.cast(); + for (int i = 0; i < ints.size(); i++) { + BigInteger msg = ints.get(i); + // Calculate the cumulative factorial and send it to the client. + lastMultiplier = msg; + factorial = factorial.multiply(msg); + ctx.write(factorial); + } + msgs.recycle(); } @Override diff --git a/example/src/main/java/io/netty/example/filetransfer/FileServer.java b/example/src/main/java/io/netty/example/filetransfer/FileServer.java index 8b4a182722..efe864a9a7 100644 --- a/example/src/main/java/io/netty/example/filetransfer/FileServer.java +++ b/example/src/main/java/io/netty/example/filetransfer/FileServer.java @@ -18,15 +18,13 @@ package io.netty.example.filetransfer; import io.netty.bootstrap.ServerBootstrap; import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.ChannelInboundMessageHandlerAdapter; +import io.netty.channel.ChannelInboundHandlerAdapter; import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelOption; -import io.netty.channel.ChannelProgressiveFuture; -import io.netty.channel.ChannelProgressiveFutureListener; -import io.netty.channel.ChannelProgressivePromise; import io.netty.channel.DefaultFileRegion; import io.netty.channel.EventLoopGroup; import io.netty.channel.FileRegion; +import io.netty.channel.MessageList; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.SocketChannel; import io.netty.channel.socket.nio.NioServerSocketChannel; @@ -94,35 +92,31 @@ public class FileServer { new FileServer(port).run(); } - private static final class FileHandler extends ChannelInboundMessageHandlerAdapter { + private static final class FileHandler extends ChannelInboundHandlerAdapter { @Override - public void messageReceived(ChannelHandlerContext ctx, String msg) throws Exception { - File file = new File(msg); - if (file.exists()) { - if (!file.isFile()) { - ctx.write("Not a file: " + file + '\n'); - return; + public void messageReceived(ChannelHandlerContext ctx, MessageList messages) throws Exception { + MessageList msgs = messages.cast(); + MessageList out = MessageList.newInstance(); + + for (int i = 0; i < msgs.size(); i++) { + String msg = msgs.get(i); + File file = new File(msg); + if (file.exists()) { + if (!file.isFile()) { + ctx.write("Not a file: " + file + '\n'); + return; + } + ctx.write(file + " " + file.length() + '\n'); + FileRegion region = new DefaultFileRegion(new FileInputStream(file).getChannel(), 0, file.length()); + out.add(region); + out.add("\n"); + } else { + out.add("File not found: " + file + '\n'); } - ctx.write(file + " " + file.length() + '\n'); - FileRegion region = new DefaultFileRegion(new FileInputStream(file).getChannel(), 0, file.length()); - ChannelProgressivePromise promise = ctx.newProgressivePromise(); - promise.addListener(new ChannelProgressiveFutureListener() { - @Override - public void operationProgressed(ChannelProgressiveFuture f, long progress, long total) { - System.err.println("progress: " + progress + " / " + total); - } - - @Override - public void operationComplete(ChannelProgressiveFuture future) { - System.err.println("file transfer complete"); - } - }); - - ctx.sendFile(region, promise); - ctx.write("\n"); - } else { - ctx.write("File not found: " + file + '\n'); } + + msgs.recycle(); + ctx.write(out); } @Override diff --git a/example/src/main/java/io/netty/example/http/file/HttpStaticFileServerHandler.java b/example/src/main/java/io/netty/example/http/file/HttpStaticFileServerHandler.java index e9411ce8fc..a460789c13 100644 --- a/example/src/main/java/io/netty/example/http/file/HttpStaticFileServerHandler.java +++ b/example/src/main/java/io/netty/example/http/file/HttpStaticFileServerHandler.java @@ -19,7 +19,8 @@ import io.netty.buffer.Unpooled; import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelFutureListener; import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.ChannelInboundMessageHandlerAdapter; +import io.netty.channel.ChannelInboundHandlerAdapter; +import io.netty.channel.MessageList; import io.netty.handler.codec.http.DefaultFullHttpResponse; import io.netty.handler.codec.http.DefaultHttpResponse; import io.netty.handler.codec.http.FullHttpRequest; @@ -27,6 +28,7 @@ import io.netty.handler.codec.http.FullHttpResponse; import io.netty.handler.codec.http.HttpHeaders; import io.netty.handler.codec.http.HttpResponse; import io.netty.handler.codec.http.HttpResponseStatus; +import io.netty.handler.codec.http.LastHttpContent; import io.netty.handler.stream.ChunkedFile; import io.netty.util.CharsetUtil; @@ -96,7 +98,7 @@ import static io.netty.handler.codec.http.HttpVersion.*; * * */ -public class HttpStaticFileServerHandler extends ChannelInboundMessageHandlerAdapter { +public class HttpStaticFileServerHandler extends ChannelInboundHandlerAdapter { public static final String HTTP_DATE_FORMAT = "EEE, dd MMM yyyy HH:mm:ss zzz"; public static final String HTTP_DATE_GMT_TIMEZONE = "GMT"; @@ -104,89 +106,96 @@ public class HttpStaticFileServerHandler extends ChannelInboundMessageHandlerAda @Override public void messageReceived( - ChannelHandlerContext ctx, FullHttpRequest request) throws Exception { - - if (!request.getDecoderResult().isSuccess()) { - sendError(ctx, BAD_REQUEST); - return; - } - - if (request.getMethod() != GET) { - sendError(ctx, METHOD_NOT_ALLOWED); - return; - } - - final String uri = request.getUri(); - final String path = sanitizeUri(uri); - if (path == null) { - sendError(ctx, FORBIDDEN); - return; - } - - File file = new File(path); - if (file.isHidden() || !file.exists()) { - sendError(ctx, NOT_FOUND); - return; - } - - if (file.isDirectory()) { - if (uri.endsWith("/")) { - sendListing(ctx, file); - } else { - sendRedirect(ctx, uri + '/'); + ChannelHandlerContext ctx, MessageList msgs) throws Exception { + MessageList requests = msgs.cast(); + for (int i = 0; i < requests.size(); i++) { + FullHttpRequest request = requests.get(i); + if (!request.getDecoderResult().isSuccess()) { + sendError(ctx, BAD_REQUEST); + continue; } - return; - } - if (!file.isFile()) { - sendError(ctx, FORBIDDEN); - return; - } + if (request.getMethod() != GET) { + sendError(ctx, METHOD_NOT_ALLOWED); + continue; + } - // Cache Validation - String ifModifiedSince = request.headers().get(IF_MODIFIED_SINCE); - if (ifModifiedSince != null && !ifModifiedSince.isEmpty()) { - SimpleDateFormat dateFormatter = new SimpleDateFormat(HTTP_DATE_FORMAT, Locale.US); - Date ifModifiedSinceDate = dateFormatter.parse(ifModifiedSince); + final String uri = request.getUri(); + final String path = sanitizeUri(uri); + if (path == null) { + sendError(ctx, FORBIDDEN); + continue; + } - // Only compare up to the second because the datetime format we send to the client - // does not have milliseconds - long ifModifiedSinceDateSeconds = ifModifiedSinceDate.getTime() / 1000; - long fileLastModifiedSeconds = file.lastModified() / 1000; - if (ifModifiedSinceDateSeconds == fileLastModifiedSeconds) { - sendNotModified(ctx); - return; + File file = new File(path); + if (file.isHidden() || !file.exists()) { + sendError(ctx, NOT_FOUND); + continue; + } + + if (file.isDirectory()) { + if (uri.endsWith("/")) { + sendListing(ctx, file); + } else { + sendRedirect(ctx, uri + '/'); + } + continue; + } + + if (!file.isFile()) { + sendError(ctx, FORBIDDEN); + continue; + } + + // Cache Validation + String ifModifiedSince = request.headers().get(IF_MODIFIED_SINCE); + if (ifModifiedSince != null && !ifModifiedSince.isEmpty()) { + SimpleDateFormat dateFormatter = new SimpleDateFormat(HTTP_DATE_FORMAT, Locale.US); + Date ifModifiedSinceDate = dateFormatter.parse(ifModifiedSince); + + // Only compare up to the second because the datetime format we send to the client + // does not have milliseconds + long ifModifiedSinceDateSeconds = ifModifiedSinceDate.getTime() / 1000; + long fileLastModifiedSeconds = file.lastModified() / 1000; + if (ifModifiedSinceDateSeconds == fileLastModifiedSeconds) { + sendNotModified(ctx); + continue; + } + } + + RandomAccessFile raf; + try { + raf = new RandomAccessFile(file, "r"); + } catch (FileNotFoundException fnfe) { + sendError(ctx, NOT_FOUND); + continue; + } + long fileLength = raf.length(); + + HttpResponse response = new DefaultHttpResponse(HTTP_1_1, OK); + setContentLength(response, fileLength); + setContentTypeHeader(response, file); + setDateAndCacheHeaders(response, file); + if (isKeepAlive(request)) { + response.headers().set(CONNECTION, HttpHeaders.Values.KEEP_ALIVE); + } + + MessageList out = MessageList.newInstance(); + // Write the initial line and the header. + out.add(response); + // Write the content. + out.add(new ChunkedFile(raf, 0, fileLength, 8192)); + // Write the end marker + out.add(LastHttpContent.EMPTY_LAST_CONTENT); + + ChannelFuture writeFuture = ctx.write(out); + // Decide whether to close the connection or not. + if (!isKeepAlive(request)) { + // Close the connection when the whole content is written out. + writeFuture.addListener(ChannelFutureListener.CLOSE); } } - - RandomAccessFile raf; - try { - raf = new RandomAccessFile(file, "r"); - } catch (FileNotFoundException fnfe) { - sendError(ctx, NOT_FOUND); - return; - } - long fileLength = raf.length(); - - HttpResponse response = new DefaultHttpResponse(HTTP_1_1, OK); - setContentLength(response, fileLength); - setContentTypeHeader(response, file); - setDateAndCacheHeaders(response, file); - if (isKeepAlive(request)) { - response.headers().set(CONNECTION, HttpHeaders.Values.KEEP_ALIVE); - } - - // Write the initial line and the header. - ctx.write(response); - - // Write the content. - ChannelFuture writeFuture = ctx.write(new ChunkedFile(raf, 0, fileLength, 8192)); - - // Decide whether to close the connection or not. - if (!isKeepAlive(request)) { - // Close the connection when the whole content is written out. - writeFuture.addListener(ChannelFutureListener.CLOSE); - } + msgs.releaseAllAndRecycle(); } @Override diff --git a/example/src/main/java/io/netty/example/http/snoop/HttpSnoopClientHandler.java b/example/src/main/java/io/netty/example/http/snoop/HttpSnoopClientHandler.java index 60f1c641c4..7262fde8d9 100644 --- a/example/src/main/java/io/netty/example/http/snoop/HttpSnoopClientHandler.java +++ b/example/src/main/java/io/netty/example/http/snoop/HttpSnoopClientHandler.java @@ -16,49 +16,54 @@ package io.netty.example.http.snoop; import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.ChannelInboundMessageHandlerAdapter; +import io.netty.channel.ChannelInboundHandlerAdapter; +import io.netty.channel.MessageList; import io.netty.handler.codec.http.HttpContent; import io.netty.handler.codec.http.HttpHeaders; import io.netty.handler.codec.http.HttpResponse; import io.netty.handler.codec.http.LastHttpContent; import io.netty.util.CharsetUtil; -public class HttpSnoopClientHandler extends ChannelInboundMessageHandlerAdapter { +public class HttpSnoopClientHandler extends ChannelInboundHandlerAdapter { @Override - public void messageReceived(ChannelHandlerContext ctx, Object msg) throws Exception { - if (msg instanceof HttpResponse) { - HttpResponse response = (HttpResponse) msg; + public void messageReceived(ChannelHandlerContext ctx, MessageList msgs) throws Exception { + for (int i = 0; i < msgs.size(); i++) { + Object msg = msgs.get(i); + if (msg instanceof HttpResponse) { + HttpResponse response = (HttpResponse) msg; - System.out.println("STATUS: " + response.getStatus()); - System.out.println("VERSION: " + response.getProtocolVersion()); - System.out.println(); - - if (!response.headers().isEmpty()) { - for (String name: response.headers().names()) { - for (String value: response.headers().getAll(name)) { - System.out.println("HEADER: " + name + " = " + value); - } - } + System.out.println("STATUS: " + response.getStatus()); + System.out.println("VERSION: " + response.getProtocolVersion()); System.out.println(); - } - if (HttpHeaders.isTransferEncodingChunked(response)) { - System.out.println("CHUNKED CONTENT {"); - } else { - System.out.println("CONTENT {"); - } - } - if (msg instanceof HttpContent) { - HttpContent content = (HttpContent) msg; - - System.out.print(content.content().toString(CharsetUtil.UTF_8)); - System.out.flush(); - - if (content instanceof LastHttpContent) { - System.out.println("} END OF CONTENT"); + if (!response.headers().isEmpty()) { + for (String name: response.headers().names()) { + for (String value: response.headers().getAll(name)) { + System.out.println("HEADER: " + name + " = " + value); + } + } + System.out.println(); + } + + if (HttpHeaders.isTransferEncodingChunked(response)) { + System.out.println("CHUNKED CONTENT {"); + } else { + System.out.println("CONTENT {"); + } + } + if (msg instanceof HttpContent) { + HttpContent content = (HttpContent) msg; + + System.out.print(content.content().toString(CharsetUtil.UTF_8)); + System.out.flush(); + + if (content instanceof LastHttpContent) { + System.out.println("} END OF CONTENT"); + } } } + msgs.releaseAllAndRecycle(); } @Override diff --git a/example/src/main/java/io/netty/example/http/snoop/HttpSnoopServerHandler.java b/example/src/main/java/io/netty/example/http/snoop/HttpSnoopServerHandler.java index 59c8a2da8b..178aebe984 100644 --- a/example/src/main/java/io/netty/example/http/snoop/HttpSnoopServerHandler.java +++ b/example/src/main/java/io/netty/example/http/snoop/HttpSnoopServerHandler.java @@ -17,9 +17,9 @@ package io.netty.example.http.snoop; import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; -import io.netty.channel.ChannelFutureListener; import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.ChannelInboundMessageHandlerAdapter; +import io.netty.channel.ChannelInboundHandlerAdapter; +import io.netty.channel.MessageList; import io.netty.handler.codec.DecoderResult; import io.netty.handler.codec.http.Cookie; import io.netty.handler.codec.http.CookieDecoder; @@ -44,19 +44,34 @@ import static io.netty.handler.codec.http.HttpHeaders.*; import static io.netty.handler.codec.http.HttpResponseStatus.*; import static io.netty.handler.codec.http.HttpVersion.*; -public class HttpSnoopServerHandler extends ChannelInboundMessageHandlerAdapter { +public class HttpSnoopServerHandler extends ChannelInboundHandlerAdapter { private HttpRequest request; /** Buffer that stores the response content */ private final StringBuilder buf = new StringBuilder(); @Override - public void messageReceived(ChannelHandlerContext ctx, Object msg) throws Exception { + public void messageReceived(ChannelHandlerContext ctx, MessageList msgs) throws Exception { + MessageList out = MessageList.newInstance(); + int size = msgs.size(); + try { + for (int i = 0; i < size; i ++) { + if (!messageReceived(ctx, msgs.get(i), out)) { + break; + } + } + } finally { + msgs.releaseAllAndRecycle(); + ctx.write(out); + } + } + + private boolean messageReceived(ChannelHandlerContext ctx, Object msg, MessageList out) { if (msg instanceof HttpRequest) { HttpRequest request = this.request = (HttpRequest) msg; if (is100ContinueExpected(request)) { - send100Continue(ctx); + send100Continue(out); } buf.setLength(0); @@ -119,9 +134,10 @@ public class HttpSnoopServerHandler extends ChannelInboundMessageHandlerAdapter< buf.append("\r\n"); } - writeResponse(ctx, trailer); + return writeResponse(ctx, trailer, out); } } + return true; } private static void appendDecoderResult(StringBuilder buf, HttpObject o) { @@ -135,7 +151,7 @@ public class HttpSnoopServerHandler extends ChannelInboundMessageHandlerAdapter< buf.append("\r\n"); } - private void writeResponse(ChannelHandlerContext ctx, HttpObject currentObj) { + private boolean writeResponse(ChannelHandlerContext ctx, HttpObject currentObj, MessageList out) { // Decide whether to close the connection or not. boolean keepAlive = isKeepAlive(request); // Build the response object. @@ -170,27 +186,18 @@ public class HttpSnoopServerHandler extends ChannelInboundMessageHandlerAdapter< } // Write the response. - ctx.nextOutboundMessageBuffer().add(response); + out.add(response); - // Close the non-keep-alive connection after the write operation is done. - if (!keepAlive) { - ctx.flush().addListener(ChannelFutureListener.CLOSE); - } + return keepAlive; } - private static void send100Continue(ChannelHandlerContext ctx) { + private static void send100Continue(MessageList out) { FullHttpResponse response = new DefaultFullHttpResponse(HTTP_1_1, CONTINUE); - ctx.nextOutboundMessageBuffer().add(response); + out.add(response); } @Override - public void endMessageReceived(ChannelHandlerContext ctx) throws Exception { - ctx.flush(); - } - - @Override - public void exceptionCaught( - ChannelHandlerContext ctx, Throwable cause) throws Exception { + public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { cause.printStackTrace(); ctx.close(); } diff --git a/example/src/main/java/io/netty/example/http/upload/HttpUploadClientHandler.java b/example/src/main/java/io/netty/example/http/upload/HttpUploadClientHandler.java index 0c3ee3c258..6c70bd6ebd 100644 --- a/example/src/main/java/io/netty/example/http/upload/HttpUploadClientHandler.java +++ b/example/src/main/java/io/netty/example/http/upload/HttpUploadClientHandler.java @@ -16,7 +16,8 @@ package io.netty.example.http.upload; import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.ChannelInboundMessageHandlerAdapter; +import io.netty.channel.ChannelInboundHandlerAdapter; +import io.netty.channel.MessageList; import io.netty.handler.codec.http.HttpContent; import io.netty.handler.codec.http.HttpHeaders; import io.netty.handler.codec.http.HttpResponse; @@ -28,50 +29,54 @@ import java.util.logging.Logger; /** * Handler that just dumps the contents of the response from the server */ -public class HttpUploadClientHandler extends ChannelInboundMessageHandlerAdapter { +public class HttpUploadClientHandler extends ChannelInboundHandlerAdapter { private static final Logger logger = Logger.getLogger(HttpUploadClientHandler.class.getName()); private boolean readingChunks; @Override - public void messageReceived(ChannelHandlerContext ctx, Object msg) throws Exception { - if (msg instanceof HttpResponse) { - HttpResponse response = (HttpResponse) msg; + public void messageReceived(ChannelHandlerContext ctx, MessageList msgs) throws Exception { + for (int i = 0; i < msgs.size(); i++) { + Object msg = msgs.get(i); + if (msg instanceof HttpResponse) { + HttpResponse response = (HttpResponse) msg; - logger.info("STATUS: " + response.getStatus()); - logger.info("VERSION: " + response.getProtocolVersion()); + logger.info("STATUS: " + response.getStatus()); + logger.info("VERSION: " + response.getProtocolVersion()); - if (!response.headers().isEmpty()) { - for (String name : response.headers().names()) { - for (String value : response.headers().getAll(name)) { - logger.info("HEADER: " + name + " = " + value); + if (!response.headers().isEmpty()) { + for (String name : response.headers().names()) { + for (String value : response.headers().getAll(name)) { + logger.info("HEADER: " + name + " = " + value); + } } } - } - if (response.getStatus().code() == 200 && HttpHeaders.isTransferEncodingChunked(response)) { - readingChunks = true; - logger.info("CHUNKED CONTENT {"); - } else { - logger.info("CONTENT {"); - } - } - if (msg instanceof HttpContent) { - HttpContent chunk = (HttpContent) msg; - logger.info(chunk.content().toString(CharsetUtil.UTF_8)); - - if (chunk instanceof LastHttpContent) { - if (readingChunks) { - logger.info("} END OF CHUNKED CONTENT"); + if (response.getStatus().code() == 200 && HttpHeaders.isTransferEncodingChunked(response)) { + readingChunks = true; + logger.info("CHUNKED CONTENT {"); } else { - logger.info("} END OF CONTENT"); + logger.info("CONTENT {"); } - readingChunks = false; - } else { + } + if (msg instanceof HttpContent) { + HttpContent chunk = (HttpContent) msg; logger.info(chunk.content().toString(CharsetUtil.UTF_8)); + + if (chunk instanceof LastHttpContent) { + if (readingChunks) { + logger.info("} END OF CHUNKED CONTENT"); + } else { + logger.info("} END OF CONTENT"); + } + readingChunks = false; + } else { + logger.info(chunk.content().toString(CharsetUtil.UTF_8)); + } } } + msgs.releaseAllAndRecycle(); } @Override diff --git a/example/src/main/java/io/netty/example/http/upload/HttpUploadServerHandler.java b/example/src/main/java/io/netty/example/http/upload/HttpUploadServerHandler.java index 6297213990..63adb8523f 100644 --- a/example/src/main/java/io/netty/example/http/upload/HttpUploadServerHandler.java +++ b/example/src/main/java/io/netty/example/http/upload/HttpUploadServerHandler.java @@ -15,13 +15,13 @@ */ package io.netty.example.http.upload; -import io.netty.buffer.BufUtil; import io.netty.buffer.ByteBuf; import io.netty.channel.Channel; import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelFutureListener; import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.ChannelInboundMessageHandlerAdapter; +import io.netty.channel.ChannelInboundHandlerAdapter; +import io.netty.channel.MessageList; import io.netty.handler.codec.http.Cookie; import io.netty.handler.codec.http.CookieDecoder; import io.netty.handler.codec.http.DefaultFullHttpResponse; @@ -62,7 +62,7 @@ import java.util.logging.Logger; import static io.netty.buffer.Unpooled.*; import static io.netty.handler.codec.http.HttpHeaders.Names.*; -public class HttpUploadServerHandler extends ChannelInboundMessageHandlerAdapter { +public class HttpUploadServerHandler extends ChannelInboundHandlerAdapter { private static final Logger logger = Logger.getLogger(HttpUploadServerHandler.class.getName()); @@ -96,110 +96,114 @@ public class HttpUploadServerHandler extends ChannelInboundMessageHandlerAdapter } @Override - public void messageReceived(ChannelHandlerContext ctx, Object msg) throws Exception { - if (msg instanceof HttpRequest) { - HttpRequest request = this.request = (HttpRequest) msg; - URI uri = new URI(request.getUri()); - if (!uri.getPath().startsWith("/form")) { - // Write Menu - writeMenu(ctx); - return; - } - responseContent.setLength(0); - responseContent.append("WELCOME TO THE WILD WILD WEB SERVER\r\n"); - responseContent.append("===================================\r\n"); - - responseContent.append("VERSION: " + request.getProtocolVersion().text() + "\r\n"); - - responseContent.append("REQUEST_URI: " + request.getUri() + "\r\n\r\n"); - responseContent.append("\r\n\r\n"); - - // new getMethod - List> headers = request.headers().entries(); - for (Entry entry : headers) { - responseContent.append("HEADER: " + entry.getKey() + '=' + entry.getValue() + "\r\n"); - } - responseContent.append("\r\n\r\n"); - - // new getMethod - Set cookies; - String value = request.headers().get(COOKIE); - if (value == null) { - cookies = Collections.emptySet(); - } else { - cookies = CookieDecoder.decode(value); - } - for (Cookie cookie : cookies) { - responseContent.append("COOKIE: " + cookie.toString() + "\r\n"); - } - responseContent.append("\r\n\r\n"); - - QueryStringDecoder decoderQuery = new QueryStringDecoder(request.getUri()); - Map> uriAttributes = decoderQuery.parameters(); - for (Entry> attr: uriAttributes.entrySet()) { - for (String attrVal: attr.getValue()) { - responseContent.append("URI: " + attr.getKey() + '=' + attrVal + "\r\n"); + public void messageReceived(ChannelHandlerContext ctx, MessageList msgs) throws Exception { + for (int i = 0; i < msgs.size(); i++) { + Object msg = msgs.get(i); + if (msg instanceof HttpRequest) { + HttpRequest request = this.request = (HttpRequest) msg; + URI uri = new URI(request.getUri()); + if (!uri.getPath().startsWith("/form")) { + // Write Menu + writeMenu(ctx); + return; } - } - responseContent.append("\r\n\r\n"); + responseContent.setLength(0); + responseContent.append("WELCOME TO THE WILD WILD WEB SERVER\r\n"); + responseContent.append("===================================\r\n"); - // if GET Method: should not try to create a HttpPostRequestDecoder - try { - decoder = new HttpPostRequestDecoder(factory, request); - } catch (ErrorDataDecoderException e1) { - e1.printStackTrace(); - responseContent.append(e1.getMessage()); - writeResponse(ctx.channel()); - ctx.channel().close(); - return; - } catch (IncompatibleDataDecoderException e1) { - // GET Method: should not try to create a HttpPostRequestDecoder - // So OK but stop here - responseContent.append(e1.getMessage()); - responseContent.append("\r\n\r\nEND OF GET CONTENT\r\n"); - writeResponse(ctx.channel()); - return; - } + responseContent.append("VERSION: " + request.getProtocolVersion().text() + "\r\n"); - readingChunks = HttpHeaders.isTransferEncodingChunked(request); - responseContent.append("Is Chunked: " + readingChunks + "\r\n"); - responseContent.append("IsMultipart: " + decoder.isMultipart() + "\r\n"); - if (readingChunks) { - // Chunk version - responseContent.append("Chunks: "); - readingChunks = true; - } - } + responseContent.append("REQUEST_URI: " + request.getUri() + "\r\n\r\n"); + responseContent.append("\r\n\r\n"); - // check if the decoder was constructed before - // if not it handles the form get - if (decoder != null) { - if (msg instanceof HttpContent) { - // New chunk is received - HttpContent chunk = (HttpContent) msg; + // new getMethod + List> headers = request.headers().entries(); + for (Entry entry : headers) { + responseContent.append("HEADER: " + entry.getKey() + '=' + entry.getValue() + "\r\n"); + } + responseContent.append("\r\n\r\n"); + + // new getMethod + Set cookies; + String value = request.headers().get(COOKIE); + if (value == null) { + cookies = Collections.emptySet(); + } else { + cookies = CookieDecoder.decode(value); + } + for (Cookie cookie : cookies) { + responseContent.append("COOKIE: " + cookie.toString() + "\r\n"); + } + responseContent.append("\r\n\r\n"); + + QueryStringDecoder decoderQuery = new QueryStringDecoder(request.getUri()); + Map> uriAttributes = decoderQuery.parameters(); + for (Entry> attr: uriAttributes.entrySet()) { + for (String attrVal: attr.getValue()) { + responseContent.append("URI: " + attr.getKey() + '=' + attrVal + "\r\n"); + } + } + responseContent.append("\r\n\r\n"); + + // if GET Method: should not try to create a HttpPostRequestDecoder try { - decoder.offer(chunk); + decoder = new HttpPostRequestDecoder(factory, request); } catch (ErrorDataDecoderException e1) { e1.printStackTrace(); responseContent.append(e1.getMessage()); writeResponse(ctx.channel()); ctx.channel().close(); return; - } - responseContent.append('o'); - // example of reading chunk by chunk (minimize memory usage due to - // Factory) - readHttpDataChunkByChunk(); - // example of reading only if at the end - if (chunk instanceof LastHttpContent) { - readHttpDataAllReceive(ctx.channel()); + } catch (IncompatibleDataDecoderException e1) { + // GET Method: should not try to create a HttpPostRequestDecoder + // So OK but stop here + responseContent.append(e1.getMessage()); + responseContent.append("\r\n\r\nEND OF GET CONTENT\r\n"); writeResponse(ctx.channel()); - readingChunks = false; + return; + } - reset(); + readingChunks = HttpHeaders.isTransferEncodingChunked(request); + responseContent.append("Is Chunked: " + readingChunks + "\r\n"); + responseContent.append("IsMultipart: " + decoder.isMultipart() + "\r\n"); + if (readingChunks) { + // Chunk version + responseContent.append("Chunks: "); + readingChunks = true; + } + } + + // check if the decoder was constructed before + // if not it handles the form get + if (decoder != null) { + if (msg instanceof HttpContent) { + // New chunk is received + HttpContent chunk = (HttpContent) msg; + try { + decoder.offer(chunk); + } catch (ErrorDataDecoderException e1) { + e1.printStackTrace(); + responseContent.append(e1.getMessage()); + writeResponse(ctx.channel()); + ctx.channel().close(); + return; + } + responseContent.append('o'); + // example of reading chunk by chunk (minimize memory usage due to + // Factory) + readHttpDataChunkByChunk(); + // example of reading only if at the end + if (chunk instanceof LastHttpContent) { + readHttpDataAllReceive(ctx.channel()); + writeResponse(ctx.channel()); + readingChunks = false; + + reset(); + } } } } + msgs.releaseAllAndRecycle(); } private void reset() { diff --git a/example/src/main/java/io/netty/example/http/websocketx/autobahn/AutobahnServerHandler.java b/example/src/main/java/io/netty/example/http/websocketx/autobahn/AutobahnServerHandler.java index 301d5f41fc..c106da74a3 100644 --- a/example/src/main/java/io/netty/example/http/websocketx/autobahn/AutobahnServerHandler.java +++ b/example/src/main/java/io/netty/example/http/websocketx/autobahn/AutobahnServerHandler.java @@ -19,7 +19,8 @@ import io.netty.buffer.Unpooled; import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelFutureListener; import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.ChannelInboundMessageHandlerAdapter; +import io.netty.channel.ChannelInboundHandlerAdapter; +import io.netty.channel.MessageList; import io.netty.handler.codec.http.DefaultFullHttpResponse; import io.netty.handler.codec.http.FullHttpRequest; import io.netty.handler.codec.http.FullHttpResponse; @@ -46,21 +47,28 @@ import static io.netty.handler.codec.http.HttpVersion.*; /** * Handles handshakes and messages */ -public class AutobahnServerHandler extends ChannelInboundMessageHandlerAdapter { +public class AutobahnServerHandler extends ChannelInboundHandlerAdapter { private static final Logger logger = Logger.getLogger(AutobahnServerHandler.class.getName()); private WebSocketServerHandshaker handshaker; @Override - public void messageReceived(ChannelHandlerContext ctx, Object msg) throws Exception { - if (msg instanceof FullHttpRequest) { - handleHttpRequest(ctx, (FullHttpRequest) msg); - } else if (msg instanceof WebSocketFrame) { - handleWebSocketFrame(ctx, (WebSocketFrame) msg); + public void messageReceived(ChannelHandlerContext ctx, MessageList msgs) throws Exception { + MessageList out = MessageList.newInstance(msgs.size()); + for (int i = 0; i < msgs.size(); i++) { + Object msg = msgs.get(i); + if (msg instanceof FullHttpRequest) { + handleHttpRequest(ctx, (FullHttpRequest) msg); + } else if (msg instanceof WebSocketFrame) { + handleWebSocketFrame(ctx, (WebSocketFrame) msg, out); + } } + msgs.recycle(); + ctx.write(out); } - private void handleHttpRequest(ChannelHandlerContext ctx, FullHttpRequest req) throws Exception { + private void handleHttpRequest(ChannelHandlerContext ctx, FullHttpRequest req) + throws Exception { // Handle a bad request. if (!req.getDecoderResult().isSuccess()) { sendHttpResponse(ctx, req, new DefaultFullHttpResponse(HTTP_1_1, BAD_REQUEST)); @@ -84,24 +92,24 @@ public class AutobahnServerHandler extends ChannelInboundMessageHandlerAdapter out) { if (logger.isLoggable(Level.FINE)) { logger.fine(String.format( "Channel %s received %s", ctx.channel().id(), frame.getClass().getSimpleName())); } if (frame instanceof CloseWebSocketFrame) { - handshaker.close(ctx.channel(), (CloseWebSocketFrame) frame.retain()); + handshaker.close(ctx.channel(), (CloseWebSocketFrame) frame); } else if (frame instanceof PingWebSocketFrame) { - ctx.nextOutboundMessageBuffer().add( - new PongWebSocketFrame(frame.isFinalFragment(), frame.rsv(), frame.content().retain())); + out.add(new PongWebSocketFrame(frame.isFinalFragment(), frame.rsv(), frame.content())); } else if (frame instanceof TextWebSocketFrame) { - ctx.nextOutboundMessageBuffer().add(frame.retain()); + out.add(frame); } else if (frame instanceof BinaryWebSocketFrame) { - ctx.nextOutboundMessageBuffer().add(frame.retain()); + out.add(frame); } else if (frame instanceof ContinuationWebSocketFrame) { - ctx.nextOutboundMessageBuffer().add(frame.retain()); + out.add(frame); } else if (frame instanceof PongWebSocketFrame) { + frame.release(); // Ignore } else { throw new UnsupportedOperationException(String.format("%s frame types not supported", frame.getClass() @@ -109,13 +117,6 @@ public class AutobahnServerHandler extends ChannelInboundMessageHandlerAdapter { +public class WebSocketClientHandler extends ChannelInboundHandlerAdapter { private final WebSocketClientHandshaker handshaker; private ChannelPromise handshakeFuture; @@ -79,31 +80,35 @@ public class WebSocketClientHandler extends ChannelInboundMessageHandlerAdapter< } @Override - public void messageReceived(ChannelHandlerContext ctx, Object msg) throws Exception { - Channel ch = ctx.channel(); - if (!handshaker.isHandshakeComplete()) { - handshaker.finishHandshake(ch, (FullHttpResponse) msg); - System.out.println("WebSocket Client connected!"); - handshakeFuture.setSuccess(); - return; - } + public void messageReceived(ChannelHandlerContext ctx, MessageList msgs) throws Exception { + for (int i = 0; i < msgs.size(); i++) { + Object msg = msgs.get(i); + Channel ch = ctx.channel(); + if (!handshaker.isHandshakeComplete()) { + handshaker.finishHandshake(ch, (FullHttpResponse) msg); + System.out.println("WebSocket Client connected!"); + handshakeFuture.setSuccess(); + continue; + } - if (msg instanceof FullHttpResponse) { - FullHttpResponse response = (FullHttpResponse) msg; - throw new Exception("Unexpected FullHttpResponse (getStatus=" + response.getStatus() + ", content=" - + response.content().toString(CharsetUtil.UTF_8) + ')'); - } + if (msg instanceof FullHttpResponse) { + FullHttpResponse response = (FullHttpResponse) msg; + throw new Exception("Unexpected FullHttpResponse (getStatus=" + response.getStatus() + ", content=" + + response.content().toString(CharsetUtil.UTF_8) + ')'); + } - WebSocketFrame frame = (WebSocketFrame) msg; - if (frame instanceof TextWebSocketFrame) { - TextWebSocketFrame textFrame = (TextWebSocketFrame) frame; - System.out.println("WebSocket Client received message: " + textFrame.text()); - } else if (frame instanceof PongWebSocketFrame) { - System.out.println("WebSocket Client received pong"); - } else if (frame instanceof CloseWebSocketFrame) { - System.out.println("WebSocket Client received closing"); - ch.close(); + WebSocketFrame frame = (WebSocketFrame) msg; + if (frame instanceof TextWebSocketFrame) { + TextWebSocketFrame textFrame = (TextWebSocketFrame) frame; + System.out.println("WebSocket Client received message: " + textFrame.text()); + } else if (frame instanceof PongWebSocketFrame) { + System.out.println("WebSocket Client received pong"); + } else if (frame instanceof CloseWebSocketFrame) { + System.out.println("WebSocket Client received closing"); + ch.close(); + } } + msgs.releaseAllAndRecycle(); } @Override diff --git a/example/src/main/java/io/netty/example/http/websocketx/html5/CustomTextFrameHandler.java b/example/src/main/java/io/netty/example/http/websocketx/html5/CustomTextFrameHandler.java index 7ee566d137..f3e62a373b 100644 --- a/example/src/main/java/io/netty/example/http/websocketx/html5/CustomTextFrameHandler.java +++ b/example/src/main/java/io/netty/example/http/websocketx/html5/CustomTextFrameHandler.java @@ -16,10 +16,10 @@ package io.netty.example.http.websocketx.html5; import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.ChannelInboundMessageHandlerAdapter; +import io.netty.channel.SimpleChannelInboundHandler; import io.netty.handler.codec.http.websocketx.TextWebSocketFrame; -public class CustomTextFrameHandler extends ChannelInboundMessageHandlerAdapter { +public class CustomTextFrameHandler extends SimpleChannelInboundHandler { @Override public void messageReceived(ChannelHandlerContext ctx, TextWebSocketFrame frame) throws Exception { diff --git a/example/src/main/java/io/netty/example/http/websocketx/server/WebSocketServerHandler.java b/example/src/main/java/io/netty/example/http/websocketx/server/WebSocketServerHandler.java index 4eb39247ab..0c6f130502 100644 --- a/example/src/main/java/io/netty/example/http/websocketx/server/WebSocketServerHandler.java +++ b/example/src/main/java/io/netty/example/http/websocketx/server/WebSocketServerHandler.java @@ -20,7 +20,8 @@ import io.netty.buffer.Unpooled; import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelFutureListener; import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.ChannelInboundMessageHandlerAdapter; +import io.netty.channel.ChannelInboundHandlerAdapter; +import io.netty.channel.MessageList; import io.netty.handler.codec.http.DefaultFullHttpResponse; import io.netty.handler.codec.http.FullHttpRequest; import io.netty.handler.codec.http.FullHttpResponse; @@ -45,7 +46,7 @@ import static io.netty.handler.codec.http.HttpVersion.*; /** * Handles handshakes and messages */ -public class WebSocketServerHandler extends ChannelInboundMessageHandlerAdapter { +public class WebSocketServerHandler extends ChannelInboundHandlerAdapter { private static final Logger logger = Logger.getLogger(WebSocketServerHandler.class.getName()); private static final String WEBSOCKET_PATH = "/websocket"; @@ -53,12 +54,16 @@ public class WebSocketServerHandler extends ChannelInboundMessageHandlerAdapter< private WebSocketServerHandshaker handshaker; @Override - public void messageReceived(ChannelHandlerContext ctx, Object msg) throws Exception { - if (msg instanceof FullHttpRequest) { - handleHttpRequest(ctx, (FullHttpRequest) msg); - } else if (msg instanceof WebSocketFrame) { - handleWebSocketFrame(ctx, (WebSocketFrame) msg); + public void messageReceived(ChannelHandlerContext ctx, MessageList msgs) throws Exception { + for (int i = 0; i < msgs.size(); i++) { + Object msg = msgs.get(i); + if (msg instanceof FullHttpRequest) { + handleHttpRequest(ctx, (FullHttpRequest) msg); + } else if (msg instanceof WebSocketFrame) { + handleWebSocketFrame(ctx, (WebSocketFrame) msg); + } } + msgs.releaseAllAndRecycle(); } private void handleHttpRequest(ChannelHandlerContext ctx, FullHttpRequest req) throws Exception { @@ -106,13 +111,11 @@ public class WebSocketServerHandler extends ChannelInboundMessageHandlerAdapter< // Check for closing frame if (frame instanceof CloseWebSocketFrame) { - frame.retain(); - handshaker.close(ctx.channel(), (CloseWebSocketFrame) frame); + handshaker.close(ctx.channel(), (CloseWebSocketFrame) frame.retain()); return; } if (frame instanceof PingWebSocketFrame) { - frame.content().retain(); - ctx.channel().write(new PongWebSocketFrame(frame.content())); + ctx.channel().write(new PongWebSocketFrame(frame.content().retain())); return; } if (!(frame instanceof TextWebSocketFrame)) { diff --git a/example/src/main/java/io/netty/example/http/websocketx/sslserver/WebSocketSslServerHandler.java b/example/src/main/java/io/netty/example/http/websocketx/sslserver/WebSocketSslServerHandler.java index a49b43eafa..050dd6200e 100644 --- a/example/src/main/java/io/netty/example/http/websocketx/sslserver/WebSocketSslServerHandler.java +++ b/example/src/main/java/io/netty/example/http/websocketx/sslserver/WebSocketSslServerHandler.java @@ -20,7 +20,8 @@ import io.netty.buffer.Unpooled; import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelFutureListener; import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.ChannelInboundMessageHandlerAdapter; +import io.netty.channel.ChannelInboundHandlerAdapter; +import io.netty.channel.MessageList; import io.netty.example.http.websocketx.server.WebSocketServerIndexPage; import io.netty.handler.codec.http.DefaultFullHttpResponse; import io.netty.handler.codec.http.FullHttpRequest; @@ -46,7 +47,7 @@ import static io.netty.handler.codec.http.HttpVersion.*; /** * Handles handshakes and messages */ -public class WebSocketSslServerHandler extends ChannelInboundMessageHandlerAdapter { +public class WebSocketSslServerHandler extends ChannelInboundHandlerAdapter { private static final Logger logger = Logger.getLogger(WebSocketSslServerHandler.class.getName()); private static final String WEBSOCKET_PATH = "/websocket"; @@ -54,12 +55,16 @@ public class WebSocketSslServerHandler extends ChannelInboundMessageHandlerAdapt private WebSocketServerHandshaker handshaker; @Override - public void messageReceived(ChannelHandlerContext ctx, Object msg) throws Exception { - if (msg instanceof FullHttpRequest) { - handleHttpRequest(ctx, (FullHttpRequest) msg); - } else if (msg instanceof WebSocketFrame) { - handleWebSocketFrame(ctx, (WebSocketFrame) msg); + public void messageReceived(ChannelHandlerContext ctx, MessageList msgs) throws Exception { + for (int i = 0; i < msgs.size(); i++) { + Object msg = msgs.get(i); + if (msg instanceof FullHttpRequest) { + handleHttpRequest(ctx, (FullHttpRequest) msg); + } else if (msg instanceof WebSocketFrame) { + handleWebSocketFrame(ctx, (WebSocketFrame) msg); + } } + msgs.releaseAllAndRecycle(); } private void handleHttpRequest(ChannelHandlerContext ctx, FullHttpRequest req) throws Exception { @@ -108,13 +113,11 @@ public class WebSocketSslServerHandler extends ChannelInboundMessageHandlerAdapt // Check for closing frame if (frame instanceof CloseWebSocketFrame) { - frame.retain(); - handshaker.close(ctx.channel(), (CloseWebSocketFrame) frame); + handshaker.close(ctx.channel(), (CloseWebSocketFrame) frame.retain()); return; } if (frame instanceof PingWebSocketFrame) { - frame.content().retain(); - ctx.channel().write(new PongWebSocketFrame(frame.content())); + ctx.channel().write(new PongWebSocketFrame(frame.content().retain())); return; } if (!(frame instanceof TextWebSocketFrame)) { diff --git a/example/src/main/java/io/netty/example/localecho/LocalEchoClientHandler.java b/example/src/main/java/io/netty/example/localecho/LocalEchoClientHandler.java index f6129b4ee6..c10774b644 100644 --- a/example/src/main/java/io/netty/example/localecho/LocalEchoClientHandler.java +++ b/example/src/main/java/io/netty/example/localecho/LocalEchoClientHandler.java @@ -16,13 +16,18 @@ package io.netty.example.localecho; import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.ChannelInboundMessageHandlerAdapter; +import io.netty.channel.ChannelInboundHandlerAdapter; +import io.netty.channel.MessageList; + +public class LocalEchoClientHandler extends ChannelInboundHandlerAdapter { -public class LocalEchoClientHandler extends ChannelInboundMessageHandlerAdapter { @Override - public void messageReceived(ChannelHandlerContext ctx, String msg) { - // Print as received - System.out.println(msg); + public void messageReceived(ChannelHandlerContext ctx, MessageList msgs) throws Exception { + for (int i = 0; i < msgs.size(); i++) { + // Print as received + System.out.println(msgs.get(i)); + } + msgs.releaseAllAndRecycle(); } @Override diff --git a/example/src/main/java/io/netty/example/localecho/LocalEchoServerHandler.java b/example/src/main/java/io/netty/example/localecho/LocalEchoServerHandler.java index 40f3d0cfbb..861e62d01f 100644 --- a/example/src/main/java/io/netty/example/localecho/LocalEchoServerHandler.java +++ b/example/src/main/java/io/netty/example/localecho/LocalEchoServerHandler.java @@ -16,14 +16,15 @@ package io.netty.example.localecho; import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.ChannelInboundMessageHandlerAdapter; +import io.netty.channel.ChannelInboundHandlerAdapter; +import io.netty.channel.MessageList; -public class LocalEchoServerHandler extends ChannelInboundMessageHandlerAdapter { +public class LocalEchoServerHandler extends ChannelInboundHandlerAdapter { @Override - public void messageReceived(ChannelHandlerContext ctx, String msg) { + public void messageReceived(ChannelHandlerContext ctx, MessageList msgs) throws Exception { // Write back as received - ctx.write(msg); + ctx.write(msgs.copy()); } @Override diff --git a/example/src/main/java/io/netty/example/objectecho/ObjectEchoClientHandler.java b/example/src/main/java/io/netty/example/objectecho/ObjectEchoClientHandler.java index 62acef8ddd..f4e2869237 100644 --- a/example/src/main/java/io/netty/example/objectecho/ObjectEchoClientHandler.java +++ b/example/src/main/java/io/netty/example/objectecho/ObjectEchoClientHandler.java @@ -16,7 +16,8 @@ package io.netty.example.objectecho; import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.ChannelInboundMessageHandlerAdapter; +import io.netty.channel.ChannelInboundHandlerAdapter; +import io.netty.channel.MessageList; import java.util.ArrayList; import java.util.List; @@ -28,7 +29,7 @@ import java.util.logging.Logger; * ping-pong traffic between the object echo client and server by sending the * first message to the server. */ -public class ObjectEchoClientHandler extends ChannelInboundMessageHandlerAdapter> { +public class ObjectEchoClientHandler extends ChannelInboundHandlerAdapter { private static final Logger logger = Logger.getLogger( ObjectEchoClientHandler.class.getName()); @@ -56,9 +57,9 @@ public class ObjectEchoClientHandler extends ChannelInboundMessageHandlerAdapter } @Override - public void messageReceived(ChannelHandlerContext ctx, List msg) throws Exception { + public void messageReceived(ChannelHandlerContext ctx, MessageList msgs) throws Exception { // Echo back the received object to the server. - ctx.write(msg); + ctx.write(msgs); } @Override diff --git a/example/src/main/java/io/netty/example/objectecho/ObjectEchoServerHandler.java b/example/src/main/java/io/netty/example/objectecho/ObjectEchoServerHandler.java index 712da3986a..f5f4d2ffc5 100644 --- a/example/src/main/java/io/netty/example/objectecho/ObjectEchoServerHandler.java +++ b/example/src/main/java/io/netty/example/objectecho/ObjectEchoServerHandler.java @@ -16,9 +16,9 @@ package io.netty.example.objectecho; import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.ChannelInboundMessageHandlerAdapter; +import io.netty.channel.ChannelInboundHandlerAdapter; +import io.netty.channel.MessageList; -import java.util.List; import java.util.logging.Level; import java.util.logging.Logger; @@ -26,16 +26,16 @@ import java.util.logging.Logger; * Handles both client-side and server-side handler depending on which * constructor was called. */ -public class ObjectEchoServerHandler extends ChannelInboundMessageHandlerAdapter> { +public class ObjectEchoServerHandler extends ChannelInboundHandlerAdapter { private static final Logger logger = Logger.getLogger( ObjectEchoServerHandler.class.getName()); @Override public void messageReceived( - ChannelHandlerContext ctx, List msg) throws Exception { + ChannelHandlerContext ctx, MessageList msgs) throws Exception { // Echo back the received object to the client. - ctx.write(msg); + ctx.write(msgs); } @Override diff --git a/example/src/main/java/io/netty/example/portunification/PortUnificationServerHandler.java b/example/src/main/java/io/netty/example/portunification/PortUnificationServerHandler.java index 71a0e9305e..4594fea6f0 100644 --- a/example/src/main/java/io/netty/example/portunification/PortUnificationServerHandler.java +++ b/example/src/main/java/io/netty/example/portunification/PortUnificationServerHandler.java @@ -17,13 +17,14 @@ package io.netty.example.portunification; import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.ChannelInboundByteHandlerAdapter; import io.netty.channel.ChannelPipeline; +import io.netty.channel.MessageList; import io.netty.example.factorial.BigIntegerDecoder; import io.netty.example.factorial.FactorialServerHandler; import io.netty.example.factorial.NumberEncoder; import io.netty.example.http.snoop.HttpSnoopServerHandler; import io.netty.example.securechat.SecureChatSslContextFactory; +import io.netty.handler.codec.ByteToMessageDecoder; import io.netty.handler.codec.compression.ZlibCodecFactory; import io.netty.handler.codec.compression.ZlibWrapper; import io.netty.handler.codec.http.HttpContentCompressor; @@ -37,7 +38,7 @@ import javax.net.ssl.SSLEngine; * Manipulates the current pipeline dynamically to switch protocols or enable * SSL or GZIP. */ -public class PortUnificationServerHandler extends ChannelInboundByteHandlerAdapter { +public class PortUnificationServerHandler extends ByteToMessageDecoder { private final boolean detectSsl; private final boolean detectGzip; @@ -52,7 +53,7 @@ public class PortUnificationServerHandler extends ChannelInboundByteHandlerAdapt } @Override - public void inboundBufferUpdated(ChannelHandlerContext ctx, ByteBuf in) throws Exception { + protected void decode(ChannelHandlerContext ctx, ByteBuf in, MessageList out) throws Exception { // Will use the first five bytes to detect a protocol. if (in.readableBytes() < 5) { return; diff --git a/example/src/main/java/io/netty/example/proxy/HexDumpProxyBackendHandler.java b/example/src/main/java/io/netty/example/proxy/HexDumpProxyBackendHandler.java index 614395a56e..cb917efd81 100644 --- a/example/src/main/java/io/netty/example/proxy/HexDumpProxyBackendHandler.java +++ b/example/src/main/java/io/netty/example/proxy/HexDumpProxyBackendHandler.java @@ -15,14 +15,15 @@ */ package io.netty.example.proxy; -import io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; import io.netty.channel.Channel; import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelFutureListener; import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.ChannelInboundByteHandlerAdapter; +import io.netty.channel.ChannelInboundHandlerAdapter; +import io.netty.channel.MessageList; -public class HexDumpProxyBackendHandler extends ChannelInboundByteHandlerAdapter { +public class HexDumpProxyBackendHandler extends ChannelInboundHandlerAdapter { private final Channel inboundChannel; @@ -33,14 +34,12 @@ public class HexDumpProxyBackendHandler extends ChannelInboundByteHandlerAdapter @Override public void channelActive(ChannelHandlerContext ctx) throws Exception { ctx.read(); - ctx.flush(); + ctx.write(Unpooled.EMPTY_BUFFER); } @Override - public void inboundBufferUpdated(final ChannelHandlerContext ctx, ByteBuf in) throws Exception { - ByteBuf out = inboundChannel.outboundByteBuffer(); - out.writeBytes(in); - inboundChannel.flush().addListener(new ChannelFutureListener() { + public void messageReceived(final ChannelHandlerContext ctx, MessageList msgs) throws Exception { + inboundChannel.write(msgs).addListener(new ChannelFutureListener() { @Override public void operationComplete(ChannelFuture future) throws Exception { if (future.isSuccess()) { diff --git a/example/src/main/java/io/netty/example/proxy/HexDumpProxyFrontendHandler.java b/example/src/main/java/io/netty/example/proxy/HexDumpProxyFrontendHandler.java index 5fd535a2b3..26b83d63dc 100644 --- a/example/src/main/java/io/netty/example/proxy/HexDumpProxyFrontendHandler.java +++ b/example/src/main/java/io/netty/example/proxy/HexDumpProxyFrontendHandler.java @@ -16,15 +16,16 @@ package io.netty.example.proxy; import io.netty.bootstrap.Bootstrap; -import io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; import io.netty.channel.Channel; import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelFutureListener; import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.ChannelInboundByteHandlerAdapter; +import io.netty.channel.ChannelInboundHandlerAdapter; import io.netty.channel.ChannelOption; +import io.netty.channel.MessageList; -public class HexDumpProxyFrontendHandler extends ChannelInboundByteHandlerAdapter { +public class HexDumpProxyFrontendHandler extends ChannelInboundHandlerAdapter { private final String remoteHost; private final int remotePort; @@ -63,11 +64,9 @@ public class HexDumpProxyFrontendHandler extends ChannelInboundByteHandlerAdapte } @Override - public void inboundBufferUpdated(final ChannelHandlerContext ctx, ByteBuf in) throws Exception { - ByteBuf out = outboundChannel.outboundByteBuffer(); - out.writeBytes(in); + public void messageReceived(final ChannelHandlerContext ctx, MessageList msgs) throws Exception { if (outboundChannel.isActive()) { - outboundChannel.flush().addListener(new ChannelFutureListener() { + outboundChannel.write(msgs).addListener(new ChannelFutureListener() { @Override public void operationComplete(ChannelFuture future) throws Exception { if (future.isSuccess()) { @@ -99,7 +98,7 @@ public class HexDumpProxyFrontendHandler extends ChannelInboundByteHandlerAdapte */ static void closeOnFlush(Channel ch) { if (ch.isActive()) { - ch.flush().addListener(ChannelFutureListener.CLOSE); + ch.write(Unpooled.EMPTY_BUFFER).addListener(ChannelFutureListener.CLOSE); } } } diff --git a/example/src/main/java/io/netty/example/qotm/QuoteOfTheMomentClientHandler.java b/example/src/main/java/io/netty/example/qotm/QuoteOfTheMomentClientHandler.java index cd0a4a1c3b..640a6a8b13 100644 --- a/example/src/main/java/io/netty/example/qotm/QuoteOfTheMomentClientHandler.java +++ b/example/src/main/java/io/netty/example/qotm/QuoteOfTheMomentClientHandler.java @@ -16,21 +16,24 @@ package io.netty.example.qotm; import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.ChannelInboundMessageHandlerAdapter; +import io.netty.channel.ChannelInboundHandlerAdapter; +import io.netty.channel.MessageList; import io.netty.channel.socket.DatagramPacket; import io.netty.util.CharsetUtil; -public class QuoteOfTheMomentClientHandler extends ChannelInboundMessageHandlerAdapter { +public class QuoteOfTheMomentClientHandler extends ChannelInboundHandlerAdapter { @Override - public void messageReceived( - ChannelHandlerContext ctx, DatagramPacket msg) - throws Exception { - String response = msg.content().toString(CharsetUtil.UTF_8); - if (response.startsWith("QOTM: ")) { - System.out.println("Quote of the Moment: " + response.substring(6)); - ctx.close(); + public void messageReceived(ChannelHandlerContext ctx, MessageList msgs) throws Exception { + MessageList packets = msgs.cast(); + for (int i = 0; i < packets.size(); i++) { + String response = packets.get(i).content().toString(CharsetUtil.UTF_8); + if (response.startsWith("QOTM: ")) { + System.out.println("Quote of the Moment: " + response.substring(6)); + ctx.close(); + } } + msgs.releaseAllAndRecycle(); } @Override diff --git a/example/src/main/java/io/netty/example/qotm/QuoteOfTheMomentServerHandler.java b/example/src/main/java/io/netty/example/qotm/QuoteOfTheMomentServerHandler.java index 514030a9ea..ed0c54c487 100644 --- a/example/src/main/java/io/netty/example/qotm/QuoteOfTheMomentServerHandler.java +++ b/example/src/main/java/io/netty/example/qotm/QuoteOfTheMomentServerHandler.java @@ -17,13 +17,14 @@ package io.netty.example.qotm; import io.netty.buffer.Unpooled; import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.ChannelInboundMessageHandlerAdapter; +import io.netty.channel.ChannelInboundHandlerAdapter; +import io.netty.channel.MessageList; import io.netty.channel.socket.DatagramPacket; import io.netty.util.CharsetUtil; import java.util.Random; -public class QuoteOfTheMomentServerHandler extends ChannelInboundMessageHandlerAdapter { +public class QuoteOfTheMomentServerHandler extends ChannelInboundHandlerAdapter { private static final Random random = new Random(); @@ -44,12 +45,17 @@ public class QuoteOfTheMomentServerHandler extends ChannelInboundMessageHandlerA } @Override - public void messageReceived(ChannelHandlerContext ctx, DatagramPacket msg) throws Exception { - System.err.println(msg); - if ("QOTM?".equals(msg.content().toString(CharsetUtil.UTF_8))) { - ctx.write(new DatagramPacket( - Unpooled.copiedBuffer("QOTM: " + nextQuote(), CharsetUtil.UTF_8), msg.sender())); + public void messageReceived(ChannelHandlerContext ctx, MessageList msgs) throws Exception { + MessageList packets = msgs.cast(); + for (int i = 0; i < packets.size(); i++) { + DatagramPacket packet = packets.get(i); + System.err.println(packet); + if ("QOTM?".equals(packet.content().toString(CharsetUtil.UTF_8))) { + ctx.write(new DatagramPacket( + Unpooled.copiedBuffer("QOTM: " + nextQuote(), CharsetUtil.UTF_8), packet.sender())); + } } + msgs.releaseAllAndRecycle(); } @Override diff --git a/example/src/main/java/io/netty/example/rxtx/RxtxClientHandler.java b/example/src/main/java/io/netty/example/rxtx/RxtxClientHandler.java index 01bf057bfd..34885c32e4 100644 --- a/example/src/main/java/io/netty/example/rxtx/RxtxClientHandler.java +++ b/example/src/main/java/io/netty/example/rxtx/RxtxClientHandler.java @@ -16,9 +16,10 @@ package io.netty.example.rxtx; import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.ChannelInboundMessageHandlerAdapter; +import io.netty.channel.ChannelInboundHandlerAdapter; +import io.netty.channel.MessageList; -public class RxtxClientHandler extends ChannelInboundMessageHandlerAdapter { +public class RxtxClientHandler extends ChannelInboundHandlerAdapter { @Override public void channelActive(ChannelHandlerContext ctx) { @@ -26,12 +27,16 @@ public class RxtxClientHandler extends ChannelInboundMessageHandlerAdapter msgs) throws Exception { + for (int i = 0; i < msgs.size(); i++) { + String msg = msgs.get(i).toString(); + if ("OK".equals(msg)) { + System.out.println("Serial port responded to AT"); + } else { + System.out.println("Serial port responded with not-OK: " + msg); + } } + msgs.releaseAllAndRecycle(); ctx.close(); } } diff --git a/example/src/main/java/io/netty/example/sctp/SctpEchoClientHandler.java b/example/src/main/java/io/netty/example/sctp/SctpEchoClientHandler.java index 341cfa921d..79ed5b2f14 100644 --- a/example/src/main/java/io/netty/example/sctp/SctpEchoClientHandler.java +++ b/example/src/main/java/io/netty/example/sctp/SctpEchoClientHandler.java @@ -16,10 +16,11 @@ package io.netty.example.sctp; import io.netty.buffer.ByteBuf; -import io.netty.buffer.MessageBuf; +import io.netty.buffer.ByteBufUtil; import io.netty.buffer.Unpooled; import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.ChannelInboundMessageHandlerAdapter; +import io.netty.channel.ChannelInboundHandlerAdapter; +import io.netty.channel.MessageList; import io.netty.channel.sctp.SctpMessage; import java.util.logging.Level; @@ -30,7 +31,7 @@ import java.util.logging.Logger; * traffic between the echo client and server by sending the first message to * the server. */ -public class SctpEchoClientHandler extends ChannelInboundMessageHandlerAdapter { +public class SctpEchoClientHandler extends ChannelInboundHandlerAdapter { private static final Logger logger = Logger.getLogger( SctpEchoClientHandler.class.getName()); @@ -56,10 +57,8 @@ public class SctpEchoClientHandler extends ChannelInboundMessageHandlerAdapter out = ctx.nextOutboundMessageBuffer(); - out.add(msg); - ctx.flush(); + public void messageReceived(ChannelHandlerContext ctx, MessageList messages) throws Exception { + ctx.write(messages); } @Override diff --git a/example/src/main/java/io/netty/example/sctp/SctpEchoServerHandler.java b/example/src/main/java/io/netty/example/sctp/SctpEchoServerHandler.java index 3b853c739f..1972c56bb4 100644 --- a/example/src/main/java/io/netty/example/sctp/SctpEchoServerHandler.java +++ b/example/src/main/java/io/netty/example/sctp/SctpEchoServerHandler.java @@ -15,11 +15,10 @@ */ package io.netty.example.sctp; -import io.netty.buffer.MessageBuf; import io.netty.channel.ChannelHandler.Sharable; import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.ChannelInboundMessageHandlerAdapter; -import io.netty.channel.sctp.SctpMessage; +import io.netty.channel.ChannelInboundHandlerAdapter; +import io.netty.channel.MessageList; import java.util.logging.Level; import java.util.logging.Logger; @@ -28,7 +27,7 @@ import java.util.logging.Logger; * Handler implementation for the SCTP echo server. */ @Sharable -public class SctpEchoServerHandler extends ChannelInboundMessageHandlerAdapter { +public class SctpEchoServerHandler extends ChannelInboundHandlerAdapter { private static final Logger logger = Logger.getLogger( SctpEchoServerHandler.class.getName()); @@ -41,9 +40,7 @@ public class SctpEchoServerHandler extends ChannelInboundMessageHandlerAdapter out = ctx.nextOutboundMessageBuffer(); - out.add(msg); - ctx.flush(); + public void messageReceived(ChannelHandlerContext ctx, MessageList msgs) throws Exception { + ctx.write(msgs); } } diff --git a/example/src/main/java/io/netty/example/securechat/SecureChatClientHandler.java b/example/src/main/java/io/netty/example/securechat/SecureChatClientHandler.java index 4573fd6c75..99efe31b72 100644 --- a/example/src/main/java/io/netty/example/securechat/SecureChatClientHandler.java +++ b/example/src/main/java/io/netty/example/securechat/SecureChatClientHandler.java @@ -16,7 +16,8 @@ package io.netty.example.securechat; import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.ChannelInboundMessageHandlerAdapter; +import io.netty.channel.ChannelInboundHandlerAdapter; +import io.netty.channel.MessageList; import java.util.logging.Level; import java.util.logging.Logger; @@ -24,14 +25,17 @@ import java.util.logging.Logger; /** * Handles a client-side channel. */ -public class SecureChatClientHandler extends ChannelInboundMessageHandlerAdapter { +public class SecureChatClientHandler extends ChannelInboundHandlerAdapter { private static final Logger logger = Logger.getLogger( SecureChatClientHandler.class.getName()); @Override - public void messageReceived(ChannelHandlerContext ctx, String msg) throws Exception { - System.err.println(msg); + public void messageReceived(ChannelHandlerContext ctx, MessageList msgs) throws Exception { + for (int i = 0; i < msgs.size(); i++) { + System.err.println(msgs.get(i)); + } + msgs.releaseAllAndRecycle(); } @Override diff --git a/example/src/main/java/io/netty/example/securechat/SecureChatServerHandler.java b/example/src/main/java/io/netty/example/securechat/SecureChatServerHandler.java index 1b8b2334e2..882fae8e04 100644 --- a/example/src/main/java/io/netty/example/securechat/SecureChatServerHandler.java +++ b/example/src/main/java/io/netty/example/securechat/SecureChatServerHandler.java @@ -17,7 +17,8 @@ package io.netty.example.securechat; import io.netty.channel.Channel; import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.ChannelInboundMessageHandlerAdapter; +import io.netty.channel.ChannelInboundHandlerAdapter; +import io.netty.channel.MessageList; import io.netty.channel.group.ChannelGroup; import io.netty.channel.group.DefaultChannelGroup; import io.netty.handler.ssl.SslHandler; @@ -31,7 +32,7 @@ import java.util.logging.Logger; /** * Handles a server-side channel. */ -public class SecureChatServerHandler extends ChannelInboundMessageHandlerAdapter { +public class SecureChatServerHandler extends ChannelInboundHandlerAdapter { private static final Logger logger = Logger.getLogger( SecureChatServerHandler.class.getName()); @@ -60,21 +61,26 @@ public class SecureChatServerHandler extends ChannelInboundMessageHandlerAdapter } @Override - public void messageReceived(ChannelHandlerContext ctx, String request) throws Exception { - // Send the received message to all channels but the current one. - for (Channel c: channels) { - if (c != ctx.channel()) { - c.write("[" + ctx.channel().remoteAddress() + "] " + - request + '\n'); - } else { - c.write("[you] " + request + '\n'); + public void messageReceived(ChannelHandlerContext ctx, MessageList requests) throws Exception { + MessageList msgs = requests.cast(); + for (int i = 0; i < msgs.size(); i++) { + String msg = msgs.get(i); + // Send the received message to all channels but the current one. + for (Channel c: channels) { + if (c != ctx.channel()) { + c.write("[" + ctx.channel().remoteAddress() + "] " + + msg + '\n'); + } else { + c.write("[you] " + msg + '\n'); + } + } + + // Close the connection if the client has sent 'bye'. + if ("bye".equals(msg.toLowerCase())) { + ctx.close(); } } - - // Close the connection if the client has sent 'bye'. - if ("bye".equals(request.toLowerCase())) { - ctx.close(); - } + msgs.releaseAllAndRecycle(); } @Override diff --git a/example/src/main/java/io/netty/example/socksproxy/DirectClientHandler.java b/example/src/main/java/io/netty/example/socksproxy/DirectClientHandler.java index 06a6a449a3..3cd1f7843f 100644 --- a/example/src/main/java/io/netty/example/socksproxy/DirectClientHandler.java +++ b/example/src/main/java/io/netty/example/socksproxy/DirectClientHandler.java @@ -15,12 +15,11 @@ */ package io.netty.example.socksproxy; -import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.ChannelInboundByteHandlerAdapter; +import io.netty.channel.ChannelInboundHandlerAdapter; -public final class DirectClientHandler extends ChannelInboundByteHandlerAdapter { +public final class DirectClientHandler extends ChannelInboundHandlerAdapter { private static final String name = "DIRECT_CLIENT_HANDLER"; public static String getName() { @@ -42,8 +41,4 @@ public final class DirectClientHandler extends ChannelInboundByteHandlerAdapter public void exceptionCaught(ChannelHandlerContext ctx, Throwable throwable) throws Exception { cb.onFailure(ctx, throwable); } - - @Override - public void inboundBufferUpdated(ChannelHandlerContext ctx, ByteBuf byteBuf) throws Exception { - } } diff --git a/example/src/main/java/io/netty/example/socksproxy/RelayHandler.java b/example/src/main/java/io/netty/example/socksproxy/RelayHandler.java index b148b5d8fb..c05f2d1494 100644 --- a/example/src/main/java/io/netty/example/socksproxy/RelayHandler.java +++ b/example/src/main/java/io/netty/example/socksproxy/RelayHandler.java @@ -15,13 +15,14 @@ */ package io.netty.example.socksproxy; -import io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; import io.netty.channel.Channel; import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.ChannelInboundByteHandlerAdapter; +import io.netty.channel.ChannelInboundHandlerAdapter; +import io.netty.channel.MessageList; -public final class RelayHandler extends ChannelInboundByteHandlerAdapter { +public final class RelayHandler extends ChannelInboundHandlerAdapter { private static final String name = "RELAY_HANDLER"; public static String getName() { @@ -36,15 +37,13 @@ public final class RelayHandler extends ChannelInboundByteHandlerAdapter { @Override public void channelActive(ChannelHandlerContext ctx) throws Exception { - ctx.flush(); + ctx.write(Unpooled.EMPTY_BUFFER); } @Override - public void inboundBufferUpdated(ChannelHandlerContext ctx, ByteBuf in) throws Exception { - ByteBuf out = relayChannel.outboundByteBuffer(); - out.writeBytes(in); + public void messageReceived(ChannelHandlerContext ctx, MessageList msgs) throws Exception { if (relayChannel.isActive()) { - relayChannel.flush(); + relayChannel.write(msgs); } } diff --git a/example/src/main/java/io/netty/example/socksproxy/SocksServerConnectHandler.java b/example/src/main/java/io/netty/example/socksproxy/SocksServerConnectHandler.java index f65dcf8008..89fb5af1d1 100644 --- a/example/src/main/java/io/netty/example/socksproxy/SocksServerConnectHandler.java +++ b/example/src/main/java/io/netty/example/socksproxy/SocksServerConnectHandler.java @@ -21,15 +21,15 @@ import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelFutureListener; import io.netty.channel.ChannelHandler; import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.ChannelInboundMessageHandlerAdapter; import io.netty.channel.ChannelOption; +import io.netty.channel.SimpleChannelInboundHandler; import io.netty.channel.socket.nio.NioSocketChannel; import io.netty.handler.codec.socks.SocksCmdRequest; import io.netty.handler.codec.socks.SocksCmdResponse; import io.netty.handler.codec.socks.SocksCmdStatus; @ChannelHandler.Sharable -public final class SocksServerConnectHandler extends ChannelInboundMessageHandlerAdapter { +public final class SocksServerConnectHandler extends SimpleChannelInboundHandler { private static final String name = "SOCKS_SERVER_CONNECT_HANDLER"; public static String getName() { diff --git a/example/src/main/java/io/netty/example/socksproxy/SocksServerHandler.java b/example/src/main/java/io/netty/example/socksproxy/SocksServerHandler.java index fdba9226d0..19739f84ba 100644 --- a/example/src/main/java/io/netty/example/socksproxy/SocksServerHandler.java +++ b/example/src/main/java/io/netty/example/socksproxy/SocksServerHandler.java @@ -17,7 +17,7 @@ package io.netty.example.socksproxy; import io.netty.channel.ChannelHandler; import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.ChannelInboundMessageHandlerAdapter; +import io.netty.channel.SimpleChannelInboundHandler; import io.netty.handler.codec.socks.SocksAuthResponse; import io.netty.handler.codec.socks.SocksAuthScheme; import io.netty.handler.codec.socks.SocksAuthStatus; @@ -29,7 +29,7 @@ import io.netty.handler.codec.socks.SocksRequest; @ChannelHandler.Sharable -public final class SocksServerHandler extends ChannelInboundMessageHandlerAdapter { +public final class SocksServerHandler extends SimpleChannelInboundHandler { private static final String name = "SOCKS_SERVER_HANDLER"; public static String getName() { @@ -56,8 +56,7 @@ public final class SocksServerHandler extends ChannelInboundMessageHandlerAdapte if (req.cmdType() == SocksCmdType.CONNECT) { ctx.pipeline().addLast(SocksServerConnectHandler.getName(), new SocksServerConnectHandler()); ctx.pipeline().remove(this); - ctx.nextInboundMessageBuffer().add(socksRequest); - ctx.fireInboundBufferUpdated(); + ctx.fireMessageReceived(socksRequest); } else { ctx.close(); } diff --git a/example/src/main/java/io/netty/example/socksproxy/SocksServerUtils.java b/example/src/main/java/io/netty/example/socksproxy/SocksServerUtils.java index 4e0e7b147d..577b9debbe 100644 --- a/example/src/main/java/io/netty/example/socksproxy/SocksServerUtils.java +++ b/example/src/main/java/io/netty/example/socksproxy/SocksServerUtils.java @@ -15,6 +15,7 @@ */ package io.netty.example.socksproxy; +import io.netty.buffer.Unpooled; import io.netty.channel.Channel; import io.netty.channel.ChannelFutureListener; @@ -29,7 +30,7 @@ public final class SocksServerUtils { */ public static void closeOnFlush(Channel ch) { if (ch.isActive()) { - ch.flush().addListener(ChannelFutureListener.CLOSE); + ch.write(Unpooled.EMPTY_BUFFER).addListener(ChannelFutureListener.CLOSE); } } } diff --git a/example/src/main/java/io/netty/example/telnet/TelnetClientHandler.java b/example/src/main/java/io/netty/example/telnet/TelnetClientHandler.java index cfb4b0e51a..f1ef0ca9d9 100644 --- a/example/src/main/java/io/netty/example/telnet/TelnetClientHandler.java +++ b/example/src/main/java/io/netty/example/telnet/TelnetClientHandler.java @@ -17,7 +17,7 @@ package io.netty.example.telnet; import io.netty.channel.ChannelHandler.Sharable; import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.ChannelInboundMessageHandlerAdapter; +import io.netty.channel.SimpleChannelInboundHandler; import java.util.logging.Level; import java.util.logging.Logger; @@ -26,14 +26,13 @@ import java.util.logging.Logger; * Handles a client-side channel. */ @Sharable -public class TelnetClientHandler extends ChannelInboundMessageHandlerAdapter { +public class TelnetClientHandler extends SimpleChannelInboundHandler { private static final Logger logger = Logger.getLogger( TelnetClientHandler.class.getName()); @Override - public void messageReceived(ChannelHandlerContext ctx, String msg) throws Exception { - // Print out the line received from the server. + protected void messageReceived(ChannelHandlerContext ctx, String msg) throws Exception { System.err.println(msg); } diff --git a/example/src/main/java/io/netty/example/telnet/TelnetServerHandler.java b/example/src/main/java/io/netty/example/telnet/TelnetServerHandler.java index a3bf128c10..e871a6d326 100644 --- a/example/src/main/java/io/netty/example/telnet/TelnetServerHandler.java +++ b/example/src/main/java/io/netty/example/telnet/TelnetServerHandler.java @@ -19,7 +19,8 @@ import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelFutureListener; import io.netty.channel.ChannelHandler.Sharable; import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.ChannelInboundMessageHandlerAdapter; +import io.netty.channel.ChannelInboundHandlerAdapter; +import io.netty.channel.MessageList; import java.net.InetAddress; import java.util.Date; @@ -30,7 +31,7 @@ import java.util.logging.Logger; * Handles a server-side channel. */ @Sharable -public class TelnetServerHandler extends ChannelInboundMessageHandlerAdapter { +public class TelnetServerHandler extends ChannelInboundHandlerAdapter { private static final Logger logger = Logger.getLogger( TelnetServerHandler.class.getName()); @@ -44,28 +45,34 @@ public class TelnetServerHandler extends ChannelInboundMessageHandlerAdapter msgs) throws Exception { + MessageList requests = msgs.cast(); + for (int i = 0; i < requests.size(); i++) { + String request = requests.get(i); - // We do not need to write a ChannelBuffer here. - // We know the encoder inserted at TelnetPipelineFactory will do the conversion. - ChannelFuture future = ctx.write(response); + // Generate and write a response. + String response; + boolean close = false; + if (request.isEmpty()) { + response = "Please type something.\r\n"; + } else if ("bye".equals(request.toLowerCase())) { + response = "Have a good day!\r\n"; + close = true; + } else { + response = "Did you say '" + request + "'?\r\n"; + } - // Close the connection after sending 'Have a good day!' - // if the client has sent 'bye'. - if (close) { - future.addListener(ChannelFutureListener.CLOSE); + // We do not need to write a ChannelBuffer here. + // We know the encoder inserted at TelnetPipelineFactory will do the conversion. + ChannelFuture future = ctx.write(response); + + // Close the connection after sending 'Have a good day!' + // if the client has sent 'bye'. + if (close) { + future.addListener(ChannelFutureListener.CLOSE); + } } + msgs.releaseAllAndRecycle(); } @Override diff --git a/example/src/main/java/io/netty/example/udt/echo/bytes/ByteEchoClientHandler.java b/example/src/main/java/io/netty/example/udt/echo/bytes/ByteEchoClientHandler.java index 4e8d401bf3..02681f8912 100644 --- a/example/src/main/java/io/netty/example/udt/echo/bytes/ByteEchoClientHandler.java +++ b/example/src/main/java/io/netty/example/udt/echo/bytes/ByteEchoClientHandler.java @@ -20,9 +20,8 @@ import com.yammer.metrics.core.Meter; import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.ChannelHandlerUtil; -import io.netty.channel.ChannelInboundByteHandlerAdapter; -import io.netty.channel.ChannelOption; +import io.netty.channel.ChannelInboundHandlerAdapter; +import io.netty.channel.MessageList; import io.netty.channel.udt.nio.NioUdtProvider; import java.util.concurrent.TimeUnit; @@ -34,7 +33,7 @@ import java.util.logging.Logger; * traffic between the echo client and server by sending the first message to * the server on activation. */ -public class ByteEchoClientHandler extends ChannelInboundByteHandlerAdapter { +public class ByteEchoClientHandler extends ChannelInboundHandlerAdapter { private static final Logger log = Logger.getLogger(ByteEchoClientHandler.class.getName()); @@ -58,13 +57,14 @@ public class ByteEchoClientHandler extends ChannelInboundByteHandlerAdapter { } @Override - public void inboundBufferUpdated(final ChannelHandlerContext ctx, - final ByteBuf in) { - meter.mark(in.readableBytes()); - final ByteBuf out = ctx.nextOutboundByteBuffer(); - out.discardReadBytes(); - out.writeBytes(in); - ctx.flush(); + public void messageReceived(ChannelHandlerContext ctx, MessageList msgs) throws Exception { + MessageList buffers = msgs.cast(); + + for (int i = 0; i < buffers.size(); i++) { + ByteBuf buf = buffers.get(i); + meter.mark(buf.readableBytes()); + } + ctx.write(buffers); } @Override @@ -74,11 +74,4 @@ public class ByteEchoClientHandler extends ChannelInboundByteHandlerAdapter { ctx.close(); } - @Override - public ByteBuf newInboundBuffer(final ChannelHandlerContext ctx) - throws Exception { - return ChannelHandlerUtil.allocate(ctx, - ctx.channel().config().getOption(ChannelOption.SO_RCVBUF)); - } - } diff --git a/example/src/main/java/io/netty/example/udt/echo/bytes/ByteEchoServerHandler.java b/example/src/main/java/io/netty/example/udt/echo/bytes/ByteEchoServerHandler.java index 1cc16e24a7..af3eebedee 100644 --- a/example/src/main/java/io/netty/example/udt/echo/bytes/ByteEchoServerHandler.java +++ b/example/src/main/java/io/netty/example/udt/echo/bytes/ByteEchoServerHandler.java @@ -15,12 +15,10 @@ */ package io.netty.example.udt.echo.bytes; -import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandler.Sharable; import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.ChannelHandlerUtil; -import io.netty.channel.ChannelInboundByteHandlerAdapter; -import io.netty.channel.ChannelOption; +import io.netty.channel.ChannelInboundHandlerAdapter; +import io.netty.channel.MessageList; import io.netty.channel.udt.nio.NioUdtProvider; import java.util.logging.Level; @@ -30,17 +28,13 @@ import java.util.logging.Logger; * Handler implementation for the echo server. */ @Sharable -public class ByteEchoServerHandler extends ChannelInboundByteHandlerAdapter { +public class ByteEchoServerHandler extends ChannelInboundHandlerAdapter { private static final Logger log = Logger.getLogger(ByteEchoServerHandler.class.getName()); @Override - public void inboundBufferUpdated(final ChannelHandlerContext ctx, - final ByteBuf in) { - final ByteBuf out = ctx.nextOutboundByteBuffer(); - out.discardReadBytes(); - out.writeBytes(in); - ctx.flush(); + public void messageReceived(final ChannelHandlerContext ctx, MessageList msgs) { + ctx.write(msgs); } @Override @@ -55,11 +49,4 @@ public class ByteEchoServerHandler extends ChannelInboundByteHandlerAdapter { log.info("ECHO active " + NioUdtProvider.socketUDT(ctx.channel()).toStringOptions()); } - @Override - public ByteBuf newInboundBuffer(final ChannelHandlerContext ctx) - throws Exception { - return ChannelHandlerUtil.allocate(ctx, - ctx.channel().config().getOption(ChannelOption.SO_RCVBUF)); - } - } diff --git a/example/src/main/java/io/netty/example/udt/echo/message/MsgEchoClientHandler.java b/example/src/main/java/io/netty/example/udt/echo/message/MsgEchoClientHandler.java index 18d6b8825e..544a3ff1ea 100644 --- a/example/src/main/java/io/netty/example/udt/echo/message/MsgEchoClientHandler.java +++ b/example/src/main/java/io/netty/example/udt/echo/message/MsgEchoClientHandler.java @@ -18,10 +18,10 @@ package io.netty.example.udt.echo.message; import com.yammer.metrics.Metrics; import com.yammer.metrics.core.Meter; import io.netty.buffer.ByteBuf; -import io.netty.buffer.MessageBuf; import io.netty.buffer.Unpooled; import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.ChannelInboundMessageHandlerAdapter; +import io.netty.channel.ChannelInboundHandlerAdapter; +import io.netty.channel.MessageList; import io.netty.channel.udt.UdtMessage; import io.netty.channel.udt.nio.NioUdtProvider; @@ -34,8 +34,7 @@ import java.util.logging.Logger; * traffic between the echo client and server by sending the first message to * the server on activation. */ -public class MsgEchoClientHandler extends - ChannelInboundMessageHandlerAdapter { +public class MsgEchoClientHandler extends ChannelInboundHandlerAdapter { private static final Logger log = Logger.getLogger(MsgEchoClientHandler.class.getName()); @@ -55,9 +54,7 @@ public class MsgEchoClientHandler extends @Override public void channelActive(final ChannelHandlerContext ctx) throws Exception { log.info("ECHO active " + NioUdtProvider.socketUDT(ctx.channel()).toStringOptions()); - final MessageBuf out = ctx.nextOutboundMessageBuffer(); - out.add(message); - ctx.flush(); + ctx.write(message); } @Override @@ -68,13 +65,13 @@ public class MsgEchoClientHandler extends } @Override - public void messageReceived(final ChannelHandlerContext ctx, - final UdtMessage message) throws Exception { - final ByteBuf byteBuf = message.content(); - meter.mark(byteBuf.readableBytes()); - final MessageBuf out = ctx.nextOutboundMessageBuffer(); - out.add(message.retain()); - ctx.flush(); - } + public void messageReceived(ChannelHandlerContext ctx, MessageList msgs) throws Exception { + MessageList buffers = msgs.cast(); + for (int i = 0; i < buffers.size(); i++) { + UdtMessage message = buffers.get(i); + meter.mark(message.content().readableBytes()); + } + ctx.write(msgs); + } } diff --git a/example/src/main/java/io/netty/example/udt/echo/message/MsgEchoServerHandler.java b/example/src/main/java/io/netty/example/udt/echo/message/MsgEchoServerHandler.java index fa17c441e9..b08e471cf0 100644 --- a/example/src/main/java/io/netty/example/udt/echo/message/MsgEchoServerHandler.java +++ b/example/src/main/java/io/netty/example/udt/echo/message/MsgEchoServerHandler.java @@ -15,11 +15,10 @@ */ package io.netty.example.udt.echo.message; -import io.netty.buffer.MessageBuf; import io.netty.channel.ChannelHandler.Sharable; import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.ChannelInboundMessageHandlerAdapter; -import io.netty.channel.udt.UdtMessage; +import io.netty.channel.ChannelInboundHandlerAdapter; +import io.netty.channel.MessageList; import io.netty.channel.udt.nio.NioUdtProvider; import java.util.logging.Level; @@ -29,8 +28,7 @@ import java.util.logging.Logger; * Handler implementation for the echo server. */ @Sharable -public class MsgEchoServerHandler extends - ChannelInboundMessageHandlerAdapter { +public class MsgEchoServerHandler extends ChannelInboundHandlerAdapter { private static final Logger log = Logger.getLogger(MsgEchoServerHandler.class.getName()); @@ -47,10 +45,7 @@ public class MsgEchoServerHandler extends } @Override - public void messageReceived(final ChannelHandlerContext ctx, - final UdtMessage message) throws Exception { - final MessageBuf out = ctx.nextOutboundMessageBuffer(); - out.add(message.retain()); - ctx.flush(); + public void messageReceived(ChannelHandlerContext ctx, MessageList msgs) throws Exception { + ctx.write(msgs); } } diff --git a/example/src/main/java/io/netty/example/udt/echo/rendezvous/MsgEchoPeerHandler.java b/example/src/main/java/io/netty/example/udt/echo/rendezvous/MsgEchoPeerHandler.java index 519f1d68de..7a78961ef4 100644 --- a/example/src/main/java/io/netty/example/udt/echo/rendezvous/MsgEchoPeerHandler.java +++ b/example/src/main/java/io/netty/example/udt/echo/rendezvous/MsgEchoPeerHandler.java @@ -18,10 +18,10 @@ package io.netty.example.udt.echo.rendezvous; import com.yammer.metrics.Metrics; import com.yammer.metrics.core.Meter; import io.netty.buffer.ByteBuf; -import io.netty.buffer.MessageBuf; import io.netty.buffer.Unpooled; import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.ChannelInboundMessageHandlerAdapter; +import io.netty.channel.ChannelInboundHandlerAdapter; +import io.netty.channel.MessageList; import io.netty.channel.udt.UdtMessage; import io.netty.channel.udt.nio.NioUdtProvider; @@ -35,7 +35,7 @@ import java.util.logging.Logger; * activation. */ public class MsgEchoPeerHandler extends - ChannelInboundMessageHandlerAdapter { + ChannelInboundHandlerAdapter { private static final Logger log = Logger.getLogger(MsgEchoPeerHandler.class.getName()); @@ -55,9 +55,7 @@ public class MsgEchoPeerHandler extends @Override public void channelActive(final ChannelHandlerContext ctx) throws Exception { log.info("ECHO active " + NioUdtProvider.socketUDT(ctx.channel()).toStringOptions()); - final MessageBuf out = ctx.nextOutboundMessageBuffer(); - out.add(message); - ctx.flush(); + ctx.write(message); } @Override @@ -68,13 +66,13 @@ public class MsgEchoPeerHandler extends } @Override - public void messageReceived(final ChannelHandlerContext ctx, - final UdtMessage message) throws Exception { - final ByteBuf byteBuf = message.content(); - meter.mark(byteBuf.readableBytes()); - final MessageBuf out = ctx.nextOutboundMessageBuffer(); - out.add(message.retain()); - ctx.flush(); - } + public void messageReceived(ChannelHandlerContext ctx, MessageList messages) throws Exception { + MessageList msgs = messages.cast(); + for (int i = 0; i < msgs.size(); i++) { + UdtMessage message = msgs.get(i); + meter.mark(message.content().readableBytes()); + } + ctx.write(msgs); + } } diff --git a/example/src/main/java/io/netty/example/udt/echo/rendezvousBytes/ByteEchoPeerHandler.java b/example/src/main/java/io/netty/example/udt/echo/rendezvousBytes/ByteEchoPeerHandler.java index 9452aa5648..3def6e7e0d 100644 --- a/example/src/main/java/io/netty/example/udt/echo/rendezvousBytes/ByteEchoPeerHandler.java +++ b/example/src/main/java/io/netty/example/udt/echo/rendezvousBytes/ByteEchoPeerHandler.java @@ -20,9 +20,8 @@ import com.yammer.metrics.core.Meter; import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.ChannelHandlerUtil; -import io.netty.channel.ChannelInboundByteHandlerAdapter; -import io.netty.channel.ChannelOption; +import io.netty.channel.ChannelInboundHandlerAdapter; +import io.netty.channel.MessageList; import io.netty.channel.udt.nio.NioUdtProvider; import java.util.concurrent.TimeUnit; @@ -34,7 +33,7 @@ import java.util.logging.Logger; * traffic between the echo client and server by sending the first message to * the server on activation. */ -public class ByteEchoPeerHandler extends ChannelInboundByteHandlerAdapter { +public class ByteEchoPeerHandler extends ChannelInboundHandlerAdapter { private static final Logger log = Logger.getLogger(ByteEchoPeerHandler.class.getName()); private final ByteBuf message; @@ -48,12 +47,6 @@ public class ByteEchoPeerHandler extends ChannelInboundByteHandlerAdapter { } } - @Override - public ByteBuf newInboundBuffer(ChannelHandlerContext ctx) throws Exception { - return ChannelHandlerUtil.allocate(ctx, - ctx.channel().config().getOption(ChannelOption.SO_RCVBUF)); - } - @Override public void channelActive(ChannelHandlerContext ctx) throws Exception { log.info("ECHO active " + NioUdtProvider.socketUDT(ctx.channel()).toStringOptions()); @@ -67,10 +60,13 @@ public class ByteEchoPeerHandler extends ChannelInboundByteHandlerAdapter { } @Override - protected void inboundBufferUpdated(ChannelHandlerContext ctx, ByteBuf in) throws Exception { - meter.mark(in.readableBytes()); - final ByteBuf out = ctx.nextOutboundByteBuffer(); - out.writeBytes(in); - ctx.flush(); + public void messageReceived(ChannelHandlerContext ctx, MessageList msgs) throws Exception { + MessageList buffers = msgs.cast(); + + for (int i = 0; i < buffers.size(); i++) { + ByteBuf buf = buffers.get(i); + meter.mark(buf.readableBytes()); + } + ctx.write(buffers); } } diff --git a/example/src/main/java/io/netty/example/uptime/UptimeClientHandler.java b/example/src/main/java/io/netty/example/uptime/UptimeClientHandler.java index 3f61a08ce4..ca36e1502b 100644 --- a/example/src/main/java/io/netty/example/uptime/UptimeClientHandler.java +++ b/example/src/main/java/io/netty/example/uptime/UptimeClientHandler.java @@ -16,11 +16,11 @@ package io.netty.example.uptime; import io.netty.bootstrap.Bootstrap; -import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandler.Sharable; import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.ChannelInboundByteHandlerAdapter; +import io.netty.channel.ChannelInboundHandlerAdapter; import io.netty.channel.EventLoop; +import io.netty.channel.MessageList; import io.netty.handler.timeout.IdleState; import io.netty.handler.timeout.IdleStateEvent; @@ -32,7 +32,7 @@ import java.util.concurrent.TimeUnit; * connection attempt getStatus. */ @Sharable -public class UptimeClientHandler extends ChannelInboundByteHandlerAdapter { +public class UptimeClientHandler extends ChannelInboundHandlerAdapter { private final UptimeClient client; private long startTime = -1; @@ -50,9 +50,9 @@ public class UptimeClientHandler extends ChannelInboundByteHandlerAdapter { } @Override - public void inboundBufferUpdated(ChannelHandlerContext ctx, ByteBuf in) throws Exception { + public void messageReceived(ChannelHandlerContext ctx, MessageList msgs) throws Exception { // Discard received data - in.clear(); + msgs.releaseAllAndRecycle(); } @Override diff --git a/example/src/main/java/io/netty/example/worldclock/WorldClockClientHandler.java b/example/src/main/java/io/netty/example/worldclock/WorldClockClientHandler.java index 865ed9558a..6bbcb0f253 100644 --- a/example/src/main/java/io/netty/example/worldclock/WorldClockClientHandler.java +++ b/example/src/main/java/io/netty/example/worldclock/WorldClockClientHandler.java @@ -17,7 +17,8 @@ package io.netty.example.worldclock; import io.netty.channel.Channel; import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.ChannelInboundMessageHandlerAdapter; +import io.netty.channel.ChannelInboundHandlerAdapter; +import io.netty.channel.MessageList; import io.netty.example.worldclock.WorldClockProtocol.Continent; import io.netty.example.worldclock.WorldClockProtocol.LocalTime; import io.netty.example.worldclock.WorldClockProtocol.LocalTimes; @@ -34,7 +35,7 @@ import java.util.logging.Level; import java.util.logging.Logger; import java.util.regex.Pattern; -public class WorldClockClientHandler extends ChannelInboundMessageHandlerAdapter { +public class WorldClockClientHandler extends ChannelInboundHandlerAdapter { private static final Logger logger = Logger.getLogger( WorldClockClientHandler.class.getName()); @@ -95,8 +96,11 @@ public class WorldClockClientHandler extends ChannelInboundMessageHandlerAdapter } @Override - public void messageReceived(ChannelHandlerContext ctx, LocalTimes msg) throws Exception { - answer.add(msg); + public void messageReceived(ChannelHandlerContext ctx, MessageList msgs) throws Exception { + for (int i = 0; i < msgs.size(); i++) { + answer.add((LocalTimes) msgs.get(i)); + } + msgs.recycle(); } @Override diff --git a/example/src/main/java/io/netty/example/worldclock/WorldClockServerHandler.java b/example/src/main/java/io/netty/example/worldclock/WorldClockServerHandler.java index d61ada1f19..d90e28db81 100644 --- a/example/src/main/java/io/netty/example/worldclock/WorldClockServerHandler.java +++ b/example/src/main/java/io/netty/example/worldclock/WorldClockServerHandler.java @@ -16,7 +16,8 @@ package io.netty.example.worldclock; import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.ChannelInboundMessageHandlerAdapter; +import io.netty.channel.ChannelInboundHandlerAdapter; +import io.netty.channel.MessageList; import io.netty.example.worldclock.WorldClockProtocol.Continent; import io.netty.example.worldclock.WorldClockProtocol.DayOfWeek; import io.netty.example.worldclock.WorldClockProtocol.LocalTime; @@ -31,33 +32,41 @@ import java.util.logging.Logger; import static java.util.Calendar.*; -public class WorldClockServerHandler extends ChannelInboundMessageHandlerAdapter { +public class WorldClockServerHandler extends ChannelInboundHandlerAdapter { private static final Logger logger = Logger.getLogger( WorldClockServerHandler.class.getName()); @Override - public void messageReceived(ChannelHandlerContext ctx, Locations locations) throws Exception { - long currentTime = System.currentTimeMillis(); + public void messageReceived(ChannelHandlerContext ctx, MessageList msgs) throws Exception { + int size = msgs.size(); + MessageList out = MessageList.newInstance(size); + for (int i = 0; i < size; i++) { + Locations locations = (Locations) msgs.get(i); + long currentTime = System.currentTimeMillis(); - LocalTimes.Builder builder = LocalTimes.newBuilder(); - for (Location l: locations.getLocationList()) { - TimeZone tz = TimeZone.getTimeZone( - toString(l.getContinent()) + '/' + l.getCity()); - Calendar calendar = getInstance(tz); - calendar.setTimeInMillis(currentTime); + LocalTimes.Builder builder = LocalTimes.newBuilder(); + for (Location l: locations.getLocationList()) { + TimeZone tz = TimeZone.getTimeZone( + toString(l.getContinent()) + '/' + l.getCity()); + Calendar calendar = getInstance(tz); + calendar.setTimeInMillis(currentTime); - builder.addLocalTime(LocalTime.newBuilder(). - setYear(calendar.get(YEAR)). - setMonth(calendar.get(MONTH) + 1). - setDayOfMonth(calendar.get(DAY_OF_MONTH)). - setDayOfWeek(DayOfWeek.valueOf(calendar.get(DAY_OF_WEEK))). - setHour(calendar.get(HOUR_OF_DAY)). - setMinute(calendar.get(MINUTE)). - setSecond(calendar.get(SECOND)).build()); + builder.addLocalTime(LocalTime.newBuilder(). + setYear(calendar.get(YEAR)). + setMonth(calendar.get(MONTH) + 1). + setDayOfMonth(calendar.get(DAY_OF_MONTH)). + setDayOfWeek(DayOfWeek.valueOf(calendar.get(DAY_OF_WEEK))). + setHour(calendar.get(HOUR_OF_DAY)). + setMinute(calendar.get(MINUTE)). + setSecond(calendar.get(SECOND)).build()); + } + + out.add(builder.build()); } - ctx.write(builder.build()); + msgs.recycle(); + ctx.write(out); } @Override diff --git a/handler/pom.xml b/handler/pom.xml index b160b0fb46..e0d88f82f2 100644 --- a/handler/pom.xml +++ b/handler/pom.xml @@ -20,7 +20,7 @@ io.netty netty-parent - 4.0.0.Final-SNAPSHOT + 4.0.0.CR4-SNAPSHOT netty-handler @@ -39,6 +39,11 @@ netty-transport ${project.version} + + ${project.groupId} + netty-codec + ${project.version} + diff --git a/handler/src/main/java/io/netty/handler/logging/ByteLoggingHandler.java b/handler/src/main/java/io/netty/handler/logging/ByteLoggingHandler.java index dbc288ba10..3c7aaf3448 100644 --- a/handler/src/main/java/io/netty/handler/logging/ByteLoggingHandler.java +++ b/handler/src/main/java/io/netty/handler/logging/ByteLoggingHandler.java @@ -17,13 +17,11 @@ package io.netty.handler.logging; import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.ChannelHandlerUtil; -import io.netty.channel.ChannelInboundByteHandler; -import io.netty.channel.ChannelOutboundByteHandler; import io.netty.channel.ChannelPromise; +import io.netty.channel.MessageList; public class ByteLoggingHandler - extends LoggingHandler implements ChannelInboundByteHandler, ChannelOutboundByteHandler { + extends LoggingHandler { private static final String NEWLINE = String.format("%n"); @@ -108,45 +106,26 @@ public class ByteLoggingHandler } @Override - public ByteBuf newInboundBuffer(ChannelHandlerContext ctx) throws Exception { - return ChannelHandlerUtil.allocate(ctx); + public void write(ChannelHandlerContext ctx, MessageList msgs, ChannelPromise promise) throws Exception { + log(ctx, "WRITE", msgs); + ctx.write(msgs, promise); } @Override - public void discardInboundReadBytes(ChannelHandlerContext ctx) throws Exception { - ctx.inboundByteBuffer().discardSomeReadBytes(); + public void messageReceived(ChannelHandlerContext ctx, MessageList msgs) throws Exception { + log(ctx, "RECEIVED", msgs); + ctx.fireMessageReceived(msgs); } - @Override - public ByteBuf newOutboundBuffer(ChannelHandlerContext ctx) throws Exception { - return ChannelHandlerUtil.allocate(ctx); - } - - @Override - public void discardOutboundReadBytes(ChannelHandlerContext ctx) throws Exception { - ctx.outboundByteBuffer().discardSomeReadBytes(); - } - - @Override - public void inboundBufferUpdated(ChannelHandlerContext ctx) - throws Exception { - ByteBuf buf = ctx.inboundByteBuffer(); + private void log(ChannelHandlerContext ctx, String message, MessageList msgs) { if (logger.isEnabled(internalLevel)) { - logger.log(internalLevel, format(ctx, formatBuffer("RECEIVED", buf))); + for (int i = 0; i < msgs.size(); i++) { + Object msg = msgs.get(i); + if (msg instanceof ByteBuf) { + logger.log(internalLevel, format(ctx, formatBuffer(message, (ByteBuf) msg))); + } + } } - ctx.nextInboundByteBuffer().writeBytes(buf); - ctx.fireInboundBufferUpdated(); - } - - @Override - public void flush(ChannelHandlerContext ctx, ChannelPromise promise) - throws Exception { - ByteBuf buf = ctx.outboundByteBuffer(); - if (logger.isEnabled(internalLevel)) { - logger.log(internalLevel, format(ctx, formatBuffer("WRITE", buf))); - } - ctx.nextOutboundByteBuffer().writeBytes(buf); - ctx.flush(promise); } protected String formatBuffer(String message, ByteBuf buf) { diff --git a/handler/src/main/java/io/netty/handler/logging/LoggingHandler.java b/handler/src/main/java/io/netty/handler/logging/LoggingHandler.java index 145a73fecf..f0cefaf059 100644 --- a/handler/src/main/java/io/netty/handler/logging/LoggingHandler.java +++ b/handler/src/main/java/io/netty/handler/logging/LoggingHandler.java @@ -15,11 +15,13 @@ */ package io.netty.handler.logging; +import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelDuplexHandler; import io.netty.channel.ChannelHandler; import io.netty.channel.ChannelHandler.Sharable; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelPromise; +import io.netty.channel.MessageList; import io.netty.util.internal.logging.InternalLogLevel; import io.netty.util.internal.logging.InternalLogger; import io.netty.util.internal.logging.InternalLoggerFactory; @@ -35,6 +37,66 @@ public class LoggingHandler extends ChannelDuplexHandler { private static final LogLevel DEFAULT_LEVEL = LogLevel.DEBUG; + private static final String NEWLINE = String.format("%n"); + + private static final String[] BYTE2HEX = new String[256]; + private static final String[] HEXPADDING = new String[16]; + private static final String[] BYTEPADDING = new String[16]; + private static final char[] BYTE2CHAR = new char[256]; + + static { + int i; + + // Generate the lookup table for byte-to-hex-dump conversion + for (i = 0; i < 10; i ++) { + StringBuilder buf = new StringBuilder(3); + buf.append(" 0"); + buf.append(i); + BYTE2HEX[i] = buf.toString(); + } + for (; i < 16; i ++) { + StringBuilder buf = new StringBuilder(3); + buf.append(" 0"); + buf.append((char) ('a' + i - 10)); + BYTE2HEX[i] = buf.toString(); + } + for (; i < BYTE2HEX.length; i ++) { + StringBuilder buf = new StringBuilder(3); + buf.append(' '); + buf.append(Integer.toHexString(i)); + BYTE2HEX[i] = buf.toString(); + } + + // Generate the lookup table for hex dump paddings + for (i = 0; i < HEXPADDING.length; i ++) { + int padding = HEXPADDING.length - i; + StringBuilder buf = new StringBuilder(padding * 3); + for (int j = 0; j < padding; j ++) { + buf.append(" "); + } + HEXPADDING[i] = buf.toString(); + } + + // Generate the lookup table for byte dump paddings + for (i = 0; i < BYTEPADDING.length; i ++) { + int padding = BYTEPADDING.length - i; + StringBuilder buf = new StringBuilder(padding); + for (int j = 0; j < padding; j ++) { + buf.append(' '); + } + BYTEPADDING[i] = buf.toString(); + } + + // Generate the lookup table for byte-to-char conversion + for (i = 0; i < BYTE2CHAR.length; i ++) { + if (i <= 0x1f || i >= 0x7f) { + BYTE2CHAR[i] = '.'; + } else { + BYTE2CHAR[i] = (char) i; + } + } + } + protected final InternalLogger logger; protected final InternalLogLevel internalLevel; @@ -230,19 +292,100 @@ public class LoggingHandler extends ChannelDuplexHandler { } @Override - public void read(ChannelHandlerContext ctx) { - ctx.read(); + public void messageReceived(ChannelHandlerContext ctx, MessageList msgs) throws Exception { + logMessages(ctx, "RECEIVED", msgs); + ctx.fireMessageReceived(msgs); } @Override - public void flush(ChannelHandlerContext ctx, ChannelPromise promise) - throws Exception { - ctx.flush(promise); + public void write(ChannelHandlerContext ctx, MessageList msgs, ChannelPromise promise) throws Exception { + logMessages(ctx, "WRITE", msgs); + ctx.write(msgs, promise); } - @Override - public void inboundBufferUpdated(ChannelHandlerContext ctx) - throws Exception { - ctx.fireInboundBufferUpdated(); + private void logMessages(ChannelHandlerContext ctx, String message, MessageList msgs) { + if (logger.isEnabled(internalLevel)) { + int size = msgs.size(); + for (int i = 0; i < size; i ++) { + Object msg = msgs.get(i); + if (msg instanceof ByteBuf) { + logger.log(internalLevel, format(ctx, formatBuffer(message, (ByteBuf) msg))); + } else { + // ignore + } + } + } + } + + protected String formatBuffer(String message, ByteBuf buf) { + int length = buf.readableBytes(); + int rows = length / 16 + (length % 15 == 0? 0 : 1) + 4; + StringBuilder dump = new StringBuilder(rows * 80 + message.length() + 16); + + dump.append(message).append('(').append(length).append('B').append(')'); + dump.append( + NEWLINE + " +-------------------------------------------------+" + + NEWLINE + " | 0 1 2 3 4 5 6 7 8 9 a b c d e f |" + + NEWLINE + "+--------+-------------------------------------------------+----------------+"); + + final int startIndex = buf.readerIndex(); + final int endIndex = buf.writerIndex(); + + int i; + for (i = startIndex; i < endIndex; i ++) { + int relIdx = i - startIndex; + int relIdxMod16 = relIdx & 15; + if (relIdxMod16 == 0) { + dump.append(NEWLINE); + dump.append(Long.toHexString(relIdx & 0xFFFFFFFFL | 0x100000000L)); + dump.setCharAt(dump.length() - 9, '|'); + dump.append('|'); + } + dump.append(BYTE2HEX[buf.getUnsignedByte(i)]); + if (relIdxMod16 == 15) { + dump.append(" |"); + for (int j = i - 15; j <= i; j ++) { + dump.append(BYTE2CHAR[buf.getUnsignedByte(j)]); + } + dump.append('|'); + } + } + + if ((i - startIndex & 15) != 0) { + int remainder = length & 15; + dump.append(HEXPADDING[remainder]); + dump.append(" |"); + for (int j = i - remainder; j < i; j ++) { + dump.append(BYTE2CHAR[buf.getUnsignedByte(j)]); + } + dump.append(BYTEPADDING[remainder]); + dump.append('|'); + } + + dump.append( + NEWLINE + "+--------+-------------------------------------------------+----------------+"); + + return dump.toString(); + } + + protected String formatBuffer(String message, Object[] msgs, int index, int length) { + return message + '(' + length + "): " + contentToString(msgs, index, length); + } + + private static String contentToString(Object[] msgs, int index, int length) { + if (length == 0) { + return "[]"; + } + StringBuilder sb = new StringBuilder(); + sb.append('['); + for (int i = index; i < length; i++) { + Object msg = msgs[i]; + sb.append(msg); + + if (i + 1 < length) { + sb.append(", "); + } + } + return sb.append(']').toString(); } } diff --git a/handler/src/main/java/io/netty/handler/logging/MessageLoggingHandler.java b/handler/src/main/java/io/netty/handler/logging/MessageLoggingHandler.java index a1a8d431e0..87377a6048 100644 --- a/handler/src/main/java/io/netty/handler/logging/MessageLoggingHandler.java +++ b/handler/src/main/java/io/netty/handler/logging/MessageLoggingHandler.java @@ -15,17 +15,11 @@ */ package io.netty.handler.logging; -import io.netty.buffer.BufUtil; -import io.netty.buffer.MessageBuf; -import io.netty.buffer.Unpooled; import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.ChannelInboundMessageHandler; -import io.netty.channel.ChannelOutboundMessageHandler; import io.netty.channel.ChannelPromise; +import io.netty.channel.MessageList; -public class MessageLoggingHandler - extends LoggingHandler - implements ChannelInboundMessageHandler, ChannelOutboundMessageHandler { +public class MessageLoggingHandler extends LoggingHandler { public MessageLoggingHandler() { } @@ -50,54 +44,42 @@ public class MessageLoggingHandler } @Override - public MessageBuf newInboundBuffer(ChannelHandlerContext ctx) throws Exception { - return Unpooled.messageBuffer(); + public void write(ChannelHandlerContext ctx, MessageList msgs, ChannelPromise promise) throws Exception { + log("WRITE", msgs); + ctx.write(msgs); } @Override - public MessageBuf newOutboundBuffer(ChannelHandlerContext ctx) throws Exception { - return Unpooled.messageBuffer(); + public void messageReceived(ChannelHandlerContext ctx, MessageList msgs) throws Exception { + log("RECEIVED", msgs); + ctx.fireMessageReceived(msgs); } - @Override - public void inboundBufferUpdated(ChannelHandlerContext ctx) - throws Exception { - MessageBuf buf = ctx.inboundMessageBuffer(); + private void log(String message, MessageList msgs) { if (logger.isEnabled(internalLevel)) { - logger.log(internalLevel, format(ctx, formatBuffer("RECEIVED", buf))); + logger.log(internalLevel, formatBuffer(message, msgs)); } - - MessageBuf out = ctx.nextInboundMessageBuffer(); - for (;;) { - Object o = buf.poll(); - if (o == null) { - break; - } - out.add(o); - } - ctx.fireInboundBufferUpdated(); } - @Override - public void flush(ChannelHandlerContext ctx, ChannelPromise promise) - throws Exception { - MessageBuf buf = ctx.outboundMessageBuffer(); - if (logger.isEnabled(internalLevel)) { - logger.log(internalLevel, format(ctx, formatBuffer("WRITE", buf))); - } - - MessageBuf out = ctx.nextOutboundMessageBuffer(); - for (;;) { - Object o = buf.poll(); - if (o == null) { - break; - } - out.add(o); - } - ctx.flush(promise); + protected String formatBuffer(String message, MessageList msgs) { + return message + '(' + msgs.size() + "): " + contentToString(msgs); } - protected String formatBuffer(String message, MessageBuf buf) { - return message + '(' + buf.size() + "): " + BufUtil.contentToString(buf); + private static String contentToString(MessageList msgs) { + if (msgs.isEmpty()) { + return "[]"; + } + StringBuilder sb = new StringBuilder(); + sb.append('['); + int size = msgs.size(); + for (int i = 0; i < size; i++) { + Object msg = msgs.get(i); + sb.append(msg); + + if (i + 1 < size) { + sb.append(", "); + } + } + return sb.append(']').toString(); } } diff --git a/handler/src/main/java/io/netty/handler/ssl/SslHandler.java b/handler/src/main/java/io/netty/handler/ssl/SslHandler.java index bfa59600c4..93b575d5b2 100644 --- a/handler/src/main/java/io/netty/handler/ssl/SslHandler.java +++ b/handler/src/main/java/io/netty/handler/ssl/SslHandler.java @@ -15,21 +15,19 @@ */ package io.netty.handler.ssl; -import io.netty.buffer.BufUtil; import io.netty.buffer.ByteBuf; +import io.netty.buffer.ByteBufUtil; +import io.netty.buffer.Unpooled; import io.netty.channel.Channel; -import io.netty.channel.ChannelDuplexHandler; -import io.netty.channel.ChannelFlushPromiseNotifier; import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelFutureListener; import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.ChannelHandlerUtil; -import io.netty.channel.ChannelInboundByteHandler; -import io.netty.channel.ChannelOutboundByteHandler; +import io.netty.channel.ChannelInboundHandler; +import io.netty.channel.ChannelOutboundHandler; import io.netty.channel.ChannelPipeline; import io.netty.channel.ChannelPromise; -import io.netty.channel.ChannelStateHandler; -import io.netty.channel.FileRegion; +import io.netty.channel.MessageList; +import io.netty.handler.codec.ByteToMessageDecoder; import io.netty.util.concurrent.DefaultPromise; import io.netty.util.concurrent.EventExecutor; import io.netty.util.concurrent.Future; @@ -44,13 +42,14 @@ import javax.net.ssl.SSLEngine; import javax.net.ssl.SSLEngineResult; import javax.net.ssl.SSLEngineResult.Status; import javax.net.ssl.SSLException; -import java.io.EOFException; import java.io.IOException; +import java.net.SocketAddress; import java.nio.ByteBuffer; import java.nio.channels.ClosedChannelException; import java.nio.channels.DatagramChannel; import java.nio.channels.SocketChannel; -import java.nio.channels.WritableByteChannel; +import java.util.ArrayDeque; +import java.util.Queue; import java.util.concurrent.Executor; import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; @@ -71,7 +70,7 @@ import java.util.regex.Pattern; *

* Beside using the handshake {@link ChannelFuture} to get notified about the completation of the handshake it's * also possible to detect it by implement the - * {@link ChannelStateHandler#userEventTriggered(ChannelHandlerContext, Object)} + * {@link ChannelInboundHandler#userEventTriggered(ChannelHandlerContext, Object)} * method and check for a {@link SslHandshakeCompletionEvent}. * *

Handshake

@@ -152,8 +151,8 @@ import java.util.regex.Pattern; * #832 in our issue tracker. */ public class SslHandler - extends ChannelDuplexHandler - implements ChannelInboundByteHandler, ChannelOutboundByteHandler { + extends ByteToMessageDecoder + implements ChannelOutboundHandler { private static final InternalLogger logger = InternalLoggerFactory.getInstance(SslHandler.class); @@ -176,15 +175,14 @@ public class SslHandler private volatile ChannelHandlerContext ctx; private final SSLEngine engine; private final Executor delegatedTaskExecutor; - private final ChannelFlushPromiseNotifier flushFutureNotifier = new ChannelFlushPromiseNotifier(true); private final boolean startTls; private boolean sentFirstMessage; - private WritableByteChannel bufferChannel; private final LazyChannelPromise handshakePromise = new LazyChannelPromise(); private final LazyChannelPromise sslCloseFuture = new LazyChannelPromise(); private final CloseNotifyListener closeNotifyWriteListener = new CloseNotifyListener(); + private final Queue pendingUnencryptedWrites = new ArrayDeque(); private volatile long handshakeTimeoutMillis = 10000; private volatile long closeNotifyTimeoutMillis = 3000; @@ -320,7 +318,7 @@ public class SslHandler engine.closeOutbound(); future.addListener(closeNotifyWriteListener); try { - flush(ctx, future); + write(ctx, MessageList.newInstance(Unpooled.EMPTY_BUFFER), future); } catch (Exception e) { if (!future.tryFailure(e)) { logger.warn("flush() raised a masked exception.", e); @@ -345,23 +343,19 @@ public class SslHandler } @Override - public ByteBuf newInboundBuffer(ChannelHandlerContext ctx) throws Exception { - return ChannelHandlerUtil.allocate(ctx); + public void bind(ChannelHandlerContext ctx, SocketAddress localAddress, ChannelPromise promise) throws Exception { + ctx.bind(localAddress, promise); } @Override - public void discardInboundReadBytes(ChannelHandlerContext ctx) throws Exception { - ctx.inboundByteBuffer().discardSomeReadBytes(); + public void connect(ChannelHandlerContext ctx, SocketAddress remoteAddress, SocketAddress localAddress, + ChannelPromise promise) throws Exception { + ctx.connect(remoteAddress, localAddress, promise); } @Override - public ByteBuf newOutboundBuffer(ChannelHandlerContext ctx) throws Exception { - return ChannelHandlerUtil.allocate(ctx); - } - - @Override - public void discardOutboundReadBytes(ChannelHandlerContext ctx) throws Exception { - ctx.outboundByteBuffer().discardSomeReadBytes(); + public void deregister(ChannelHandlerContext ctx, ChannelPromise promise) throws Exception { + ctx.deregister(promise); } @Override @@ -382,132 +376,95 @@ public class SslHandler } @Override - public final void sendFile(ChannelHandlerContext ctx, FileRegion region, ChannelPromise promise) throws Exception { - if (bufferChannel == null) { - bufferChannel = new BufferChannel(ctx.outboundByteBuffer()); - } - long written = 0; - try { - for (;;) { - long localWritten = region.transferTo(bufferChannel, written); - if (localWritten == -1) { - checkEOF(region, written); - flush(ctx, promise); - break; - } - written += localWritten; - if (written >= region.count()) { - flush(ctx, promise); - break; - } - } - } catch (IOException e) { - promise.setFailure(e); - } finally { - region.release(); - } - } - - private static void checkEOF(FileRegion region, long writtenBytes) throws IOException { - if (writtenBytes < region.count()) { - throw new EOFException("Expected to be able to write " - + region.count() + " bytes, but only wrote " - + writtenBytes); - } - } - - private static final class BufferChannel implements WritableByteChannel { - private final ByteBuf buffer; - - BufferChannel(ByteBuf buffer) { - this.buffer = buffer; - } - @Override - public int write(ByteBuffer src) { - int bytes = src.remaining(); - buffer.writeBytes(src); - return bytes; - } - - @Override - public boolean isOpen() { - return buffer.refCnt() > 0; - } - - @Override - public void close() { - // NOOP - } - } - - @Override - public void flush(final ChannelHandlerContext ctx, ChannelPromise promise) throws Exception { - flush0(ctx, promise, false); - } - - private void flush0(ChannelHandlerContext ctx, ChannelPromise promise, boolean internal) throws Exception { - final ByteBuf in = ctx.outboundByteBuffer(); - final ByteBuf out = ctx.nextOutboundByteBuffer(); - + public void write(final ChannelHandlerContext ctx, MessageList msgs, ChannelPromise promise) + throws Exception { // Do not encrypt the first write request if this handler is // created with startTLS flag turned on. - if (!internal && startTls && !sentFirstMessage) { + if (startTls && !sentFirstMessage) { sentFirstMessage = true; - out.writeBytes(in); - ctx.flush(promise); + ctx.write(msgs, promise); return; } - - if (ctx.executor() == ctx.channel().eventLoop()) { - flushFutureNotifier.add(promise, in.readableBytes()); - } else { - synchronized (flushFutureNotifier) { - flushFutureNotifier.add(promise, in.readableBytes()); + for (int i = 0; i < msgs.size(); i++) { + ByteBuf msg = (ByteBuf) msgs.get(i); + ChannelPromise cp; + if (i + 1 == msgs.size()) { + cp = promise; + } else { + cp = ctx.newPromise(); } + pendingUnencryptedWrites.add(new PendingWrite(msg, cp)); } + flush0(ctx); + } + + private void flush0(ChannelHandlerContext ctx) throws SSLException { boolean unwrapLater = false; - int bytesConsumed = 0; + PendingWrite pending = null; + ByteBuf out = null; try { for (;;) { - SSLEngineResult result = wrap(engine, in, out); - bytesConsumed += result.bytesConsumed(); + if (out == null) { + out = ctx.alloc().buffer(); + } + pending = pendingUnencryptedWrites.peek(); + if (pending == null) { + break; + } + SSLEngineResult result = wrap(engine, pending.buf, out); + + if (!pending.buf.isReadable()) { + pending.buf.release(); + pendingUnencryptedWrites.remove(); + } + if (result.getStatus() == Status.CLOSED) { // SSLEngine has been closed already. // Any further write attempts should be denied. - if (in.isReadable()) { - in.clear(); - promise.setFailure(SSLENGINE_CLOSED); - ctx.fireExceptionCaught(SSLENGINE_CLOSED); - flush0(ctx, bytesConsumed, SSLENGINE_CLOSED); - bytesConsumed = 0; + boolean failed = false; + for (;;) { + PendingWrite w = pendingUnencryptedWrites.poll(); + if (w == null) { + break; + } + failed = true; + w.fail(SSLENGINE_CLOSED); } - break; + if (failed) { + ctx.fireExceptionCaught(SSLENGINE_CLOSED); + } + return; } else { switch (result.getHandshakeStatus()) { - case NEED_WRAP: - ctx.flush(); - continue; - case NEED_UNWRAP: - if (ctx.inboundByteBuffer().isReadable()) { - unwrapLater = true; - } - break; - case NEED_TASK: - runDelegatedTasks(); - continue; - case FINISHED: - setHandshakeSuccess(); - continue; - case NOT_HANDSHAKING: - // Workaround for TLS False Start problem reported at: - // https://github.com/netty/netty/issues/1108#issuecomment-14266970 - if (ctx.inboundByteBuffer().isReadable()) { - unwrapLater = true; - } - break; - default: - throw new IllegalStateException("Unknown handshake status: " + result.getHandshakeStatus()); + case NEED_WRAP: + if (!pending.buf.isReadable()) { + ctx.write(out, pending.promise); + } else { + ctx.write(out); + } + out = ctx.alloc().buffer(); + continue; + case NEED_UNWRAP: + if (internalBuffer().isReadable()) { + unwrapLater = true; + } + break; + case NEED_TASK: + runDelegatedTasks(); + continue; + case FINISHED: + setHandshakeSuccess(); + continue; + case NOT_HANDSHAKING: + // Workaround for TLS False Start problem reported at: + // https://github.com/netty/netty/issues/1108#issuecomment-14266970 + if (internalBuffer().isReadable()) { + unwrapLater = true; + } + break; + default: + throw new IllegalStateException("Unknown handshake status: " + result.getHandshakeStatus()); } if (result.bytesConsumed() == 0 && result.bytesProduced() == 0) { @@ -517,64 +474,88 @@ public class SslHandler } if (unwrapLater) { - inboundBufferUpdated(ctx); + decode0(ctx); } } catch (SSLException e) { setHandshakeFailure(e); throw e; } finally { - flush0(ctx, bytesConsumed); + if (out != null && out.isReadable()) { + if (pending != null && !pending.buf.isReadable()) { + ctx.write(out, pending.promise); + } else { + ctx.write(out); + } + out = null; + } else if (pending != null && !pending.buf.isReadable()) { + pending.promise.setSuccess(); + } + if (out != null) { + out.release(); + } } } - private void flush0(final ChannelHandlerContext ctx, final int bytesConsumed) { - ctx.flush(ctx.newPromise().addListener(new ChannelFutureListener() { - @Override - public void operationComplete(ChannelFuture future) throws Exception { - if (ctx.executor() == ctx.channel().eventLoop()) { - notifyFlushFutures(bytesConsumed, future); - } else { - synchronized (flushFutureNotifier) { - notifyFlushFutures(bytesConsumed, future); - } + private void flushNonAppData0(ChannelHandlerContext ctx) throws SSLException { + boolean unwrapLater = false; + ByteBuf out = null; + try { + for (;;) { + if (out == null) { + out = ctx.alloc().buffer(); + } + SSLEngineResult result = wrap(engine, Unpooled.EMPTY_BUFFER, out); + + if (result.bytesProduced() > 0) { + ctx.write(out); + out = null; + } + + switch (result.getHandshakeStatus()) { + case NEED_WRAP: + continue; + case NEED_UNWRAP: + if (internalBuffer().isReadable()) { + unwrapLater = true; + } + break; + case NEED_TASK: + runDelegatedTasks(); + continue; + case FINISHED: + setHandshakeSuccess(); + // try to flush now just in case as there may be pending write tasks + flush0(ctx); + return; + case NOT_HANDSHAKING: + // Workaround for TLS False Start problem reported at: + // https://github.com/netty/netty/issues/1108#issuecomment-14266970 + if (internalBuffer().isReadable()) { + unwrapLater = true; + } + // try to flush now just in case as there may be pending write tasks + flush0(ctx); + break; + default: + throw new IllegalStateException("Unknown handshake status: " + result.getHandshakeStatus()); + } + + if (result.bytesProduced() == 0) { + break; } } - private void notifyFlushFutures(final int bytesConsumed, ChannelFuture future) { - if (future.isSuccess()) { - flushFutureNotifier.increaseWriteCounter(bytesConsumed); - flushFutureNotifier.notifyFlushFutures(); - } else { - flushFutureNotifier.notifyFlushFutures(future.cause()); - } + if (unwrapLater) { + decode0(ctx); } - })); - } - - private void flush0(final ChannelHandlerContext ctx, final int bytesConsumed, final Throwable cause) { - ChannelFuture flushFuture = ctx.flush(ctx.newPromise().addListener(new ChannelFutureListener() { - @Override - public void operationComplete(ChannelFuture future) throws Exception { - if (ctx.executor() == ctx.channel().eventLoop()) { - notifyFlushFutures(bytesConsumed, cause, future); - } else { - synchronized (flushFutureNotifier) { - notifyFlushFutures(bytesConsumed, cause, future); - } - } + } catch (SSLException e) { + setHandshakeFailure(e); + throw e; + } finally { + if (out != null) { + out.release(); } - - private void notifyFlushFutures(int bytesConsumed, Throwable cause, ChannelFuture future) { - flushFutureNotifier.increaseWriteCounter(bytesConsumed); - if (future.isSuccess()) { - flushFutureNotifier.notifyFlushFutures(cause); - } else { - flushFutureNotifier.notifyFlushFutures(cause, future.cause()); - } - } - })); - - safeClose(ctx, flushFuture, ctx.newPromise()); + } } private static SSLEngineResult wrap(SSLEngine engine, ByteBuf in, ByteBuf out) throws SSLException { @@ -597,12 +578,7 @@ public class SslHandler // Make sure to release SSLEngine, // and notify the handshake future if the connection has been closed during handshake. setHandshakeFailure(CHANNEL_CLOSED); - - try { - inboundBufferUpdated(ctx); - } finally { - ctx.fireChannelInactive(); - } + super.channelInactive(ctx); } @Override @@ -787,8 +763,14 @@ public class SslHandler } @Override - public void inboundBufferUpdated(final ChannelHandlerContext ctx) throws Exception { - final ByteBuf in = ctx.inboundByteBuffer(); + public void decode(final ChannelHandlerContext ctx, ByteBuf in, MessageList out) throws Exception { + decode0(ctx); + } + + private ByteBuf decodeOut; + + private void decode0(final ChannelHandlerContext ctx) throws SSLException { + final ByteBuf in = internalBuffer(); if (in.readableBytes() < 5) { return; @@ -799,7 +781,7 @@ public class SslHandler if (packetLength == -1) { // Bad data - discard the buffer and raise an exception. NotSslRecordException e = new NotSslRecordException( - "not an SSL/TLS record: " + BufUtil.hexDump(in)); + "not an SSL/TLS record: " + ByteBufUtil.hexDump(in)); in.skipBytes(in.readableBytes()); ctx.fireExceptionCaught(e); setHandshakeFailure(e); @@ -808,43 +790,44 @@ public class SslHandler assert packetLength > 0; - final ByteBuf out = ctx.nextInboundByteBuffer(); - boolean wrapLater = false; int bytesProduced = 0; try { loop: for (;;) { - SSLEngineResult result = unwrap(engine, in, out); + if (decodeOut == null) { + decodeOut = ctx.alloc().buffer(); + } + SSLEngineResult result = unwrap(engine, in, decodeOut); bytesProduced += result.bytesProduced(); switch (result.getStatus()) { - case CLOSED: - // notify about the CLOSED state of the SSLEngine. See #137 - sslCloseFuture.trySuccess(ctx.channel()); - break; - case BUFFER_UNDERFLOW: - break loop; + case CLOSED: + // notify about the CLOSED state of the SSLEngine. See #137 + sslCloseFuture.trySuccess(ctx.channel()); + break; + case BUFFER_UNDERFLOW: + break loop; } switch (result.getHandshakeStatus()) { - case NEED_UNWRAP: - break; - case NEED_WRAP: - wrapLater = true; - break; - case NEED_TASK: - runDelegatedTasks(); - break; - case FINISHED: - setHandshakeSuccess(); - wrapLater = true; - continue; - case NOT_HANDSHAKING: - break; - default: - throw new IllegalStateException( - "Unknown handshake status: " + result.getHandshakeStatus()); + case NEED_UNWRAP: + break; + case NEED_WRAP: + wrapLater = true; + break; + case NEED_TASK: + runDelegatedTasks(); + break; + case FINISHED: + setHandshakeSuccess(); + wrapLater = true; + continue; + case NOT_HANDSHAKING: + break; + default: + throw new IllegalStateException( + "Unknown handshake status: " + result.getHandshakeStatus()); } if (result.bytesConsumed() == 0 && result.bytesProduced() == 0) { @@ -853,14 +836,15 @@ public class SslHandler } if (wrapLater) { - flush0(ctx, ctx.newPromise(), true); + flushNonAppData0(ctx); } } catch (SSLException e) { setHandshakeFailure(e); throw e; } finally { if (bytesProduced > 0) { - ctx.fireInboundBufferUpdated(); + ctx.fireMessageReceived(decodeOut); + decodeOut = null; } } } @@ -935,9 +919,14 @@ public class SslHandler // closeInbound() will raise an exception with bogus truncation attack warning. } } - notifyHandshakeFailure(cause); - flush0(ctx, 0, cause); + for (;;) { + PendingWrite write = pendingUnencryptedWrites.poll(); + if (write == null) { + break; + } + write.fail(cause); + } } private void notifyHandshakeFailure(Throwable cause) { @@ -961,7 +950,7 @@ public class SslHandler engine.closeOutbound(); ChannelPromise closeNotifyFuture = ctx.newPromise().addListener(closeNotifyWriteListener); - flush0(ctx, closeNotifyFuture, true); + write(ctx, MessageList.newInstance(Unpooled.EMPTY_BUFFER), closeNotifyFuture); safeClose(ctx, closeNotifyFuture, promise); } @@ -970,7 +959,7 @@ public class SslHandler this.ctx = ctx; if (ctx.channel().isActive()) { - // channelActvie() event has been fired already, which means this.channelActive() will + // channelActive() event has been fired already, which means this.channelActive() will // not be invoked. We have to initialize here instead. handshake0(); } else { @@ -1005,7 +994,7 @@ public class SslHandler }); try { engine.beginHandshake(); - flush0(ctx, ctx.newPromise(), true); + flushNonAppData0(ctx); } catch (Exception e) { notifyHandshakeFailure(e); } @@ -1024,6 +1013,7 @@ public class SslHandler @Override public void operationComplete(Future future) throws Exception { if (!future.isSuccess()) { + future.cause().printStackTrace(); ctx.close(); } } @@ -1031,7 +1021,6 @@ public class SslHandler } ctx.fireChannelActive(); } - private void safeClose( final ChannelHandlerContext ctx, ChannelFuture flushFuture, final ChannelPromise promise) { @@ -1095,4 +1084,18 @@ public class SslHandler return ctx.executor(); } } + + private static final class PendingWrite { + final ByteBuf buf; + final ChannelPromise promise; + PendingWrite(ByteBuf buf, ChannelPromise promise) { + this.buf = buf; + this.promise = promise; + } + + void fail(Throwable cause) { + buf.release(); + promise.setFailure(cause); + } + } } diff --git a/handler/src/main/java/io/netty/handler/stream/ChunkedMessageInput.java b/handler/src/main/java/io/netty/handler/stream/ChunkedMessageInput.java index b2fca7be39..52a534a625 100644 --- a/handler/src/main/java/io/netty/handler/stream/ChunkedMessageInput.java +++ b/handler/src/main/java/io/netty/handler/stream/ChunkedMessageInput.java @@ -15,7 +15,7 @@ */ package io.netty.handler.stream; -import io.netty.buffer.MessageBuf; +import io.netty.channel.MessageList; import java.util.Queue; @@ -23,6 +23,6 @@ import java.util.Queue; * {@link ChunkedInput} which reads its chunks and transfer it to a {@link Queue} * */ -public interface ChunkedMessageInput extends ChunkedInput> { +public interface ChunkedMessageInput extends ChunkedInput> { } diff --git a/handler/src/main/java/io/netty/handler/stream/ChunkedWriteHandler.java b/handler/src/main/java/io/netty/handler/stream/ChunkedWriteHandler.java index 99dd761c37..03d819e6e9 100644 --- a/handler/src/main/java/io/netty/handler/stream/ChunkedWriteHandler.java +++ b/handler/src/main/java/io/netty/handler/stream/ChunkedWriteHandler.java @@ -15,7 +15,7 @@ */ package io.netty.handler.stream; -import io.netty.buffer.MessageBuf; +import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import io.netty.channel.Channel; import io.netty.channel.ChannelDuplexHandler; @@ -23,14 +23,15 @@ import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelFutureListener; import io.netty.channel.ChannelHandler; import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.ChannelHandlerUtil; -import io.netty.channel.ChannelOutboundMessageHandler; import io.netty.channel.ChannelPipeline; import io.netty.channel.ChannelPromise; +import io.netty.channel.MessageList; import io.netty.util.internal.logging.InternalLogger; import io.netty.util.internal.logging.InternalLoggerFactory; import java.nio.channels.ClosedChannelException; +import java.util.ArrayDeque; +import java.util.Queue; import java.util.concurrent.atomic.AtomicInteger; /** @@ -65,12 +66,12 @@ import java.util.concurrent.atomic.AtomicInteger; * call {@link #resumeTransfer()}. */ public class ChunkedWriteHandler - extends ChannelDuplexHandler implements ChannelOutboundMessageHandler { + extends ChannelDuplexHandler { private static final InternalLogger logger = InternalLoggerFactory.getInstance(ChunkedWriteHandler.class); - private final MessageBuf queue = Unpooled.messageBuffer(); + private final Queue queue = new ArrayDeque(); private final int maxPendingWrites; private volatile ChannelHandlerContext ctx; private final AtomicInteger pendingWrites = new AtomicInteger(); @@ -88,11 +89,6 @@ public class ChunkedWriteHandler this.maxPendingWrites = maxPendingWrites; } - @Override - public MessageBuf newOutboundBuffer(ChannelHandlerContext ctx) throws Exception { - return queue; - } - @Override public void handlerAdded(ChannelHandlerContext ctx) throws Exception { this.ctx = ctx; @@ -142,18 +138,17 @@ public class ChunkedWriteHandler } @Override - public void flush(ChannelHandlerContext ctx, ChannelPromise promise) throws Exception { + public void write(ChannelHandlerContext ctx, MessageList msgs, ChannelPromise promise) throws Exception { + for (int i = 0; i < msgs.size(); i++) { + queue.add(msgs.get(i)); + } + msgs.recycle(); queue.add(promise); if (isWritable() || !ctx.channel().isActive()) { doFlush(ctx); } } - @Override - public void inboundBufferUpdated(ChannelHandlerContext ctx) throws Exception { - ctx.fireInboundBufferUpdated(); - } - @Override public void channelInactive(ChannelHandlerContext ctx) throws Exception { doFlush(ctx); @@ -213,6 +208,7 @@ public class ChunkedWriteHandler discard(ctx, null); return; } + MessageList messages = MessageList.newInstance(); while (isWritable()) { if (currentEvent == null) { currentEvent = queue.poll(); @@ -225,14 +221,16 @@ public class ChunkedWriteHandler final Object currentEvent = this.currentEvent; if (currentEvent instanceof ChannelPromise) { this.currentEvent = null; - ctx.flush((ChannelPromise) currentEvent); + ctx.write(messages, (ChannelPromise) currentEvent); + messages = MessageList.newInstance(); } else if (currentEvent instanceof ChunkedInput) { + MessageList out = MessageList.newInstance(); final ChunkedInput chunks = (ChunkedInput) currentEvent; boolean read; boolean endOfInput; boolean suspend; try { - read = readChunk(ctx, chunks); + read = readChunk(ctx, chunks, out); endOfInput = chunks.isEndOfInput(); if (!read) { @@ -267,7 +265,7 @@ public class ChunkedWriteHandler } pendingWrites.incrementAndGet(); - ChannelFuture f = ctx.flush(); + ChannelFuture f = ctx.write(out); if (endOfInput) { this.currentEvent = null; @@ -307,7 +305,7 @@ public class ChunkedWriteHandler }); } } else { - ChannelHandlerUtil.addToNextOutboundBuffer(ctx, currentEvent); + ctx.write(currentEvent); this.currentEvent = null; } @@ -326,11 +324,16 @@ public class ChunkedWriteHandler * @throws Exception if something goes wrong */ @SuppressWarnings("unchecked") - protected boolean readChunk(ChannelHandlerContext ctx, ChunkedInput chunks) throws Exception { + protected boolean readChunk( + @SuppressWarnings("UnusedParameters") ChannelHandlerContext ctx, + ChunkedInput chunks, MessageList out) throws Exception { if (chunks instanceof ChunkedByteInput) { - return ((ChunkedByteInput) chunks).readChunk(ctx.nextOutboundByteBuffer()); + ByteBuf buf = Unpooled.buffer(); + boolean done = ((ChunkedByteInput) chunks).readChunk(buf); + out.add(buf); + return done; } else if (chunks instanceof ChunkedMessageInput) { - return ((ChunkedMessageInput) chunks).readChunk(ctx.nextOutboundMessageBuffer()); + return ((ChunkedMessageInput) chunks).readChunk(out); } else { throw new IllegalArgumentException("ChunkedInput instance " + chunks + " not supported"); } diff --git a/handler/src/main/java/io/netty/handler/timeout/IdleStateHandler.java b/handler/src/main/java/io/netty/handler/timeout/IdleStateHandler.java index 5ccf794809..0afd0c9c05 100644 --- a/handler/src/main/java/io/netty/handler/timeout/IdleStateHandler.java +++ b/handler/src/main/java/io/netty/handler/timeout/IdleStateHandler.java @@ -21,12 +21,12 @@ import io.netty.channel.ChannelDuplexHandler; import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelFutureListener; import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.ChannelInboundHandlerAdapter; import io.netty.channel.ChannelInitializer; -import io.netty.channel.ChannelOperationHandler; +import io.netty.channel.ChannelOutboundHandler; import io.netty.channel.ChannelPromise; -import io.netty.channel.ChannelStateHandlerAdapter; +import io.netty.channel.MessageList; import io.netty.util.concurrent.EventExecutor; -import io.netty.channel.FileRegion; import java.net.SocketAddress; import java.util.concurrent.ScheduledFuture; @@ -98,7 +98,7 @@ import java.util.concurrent.TimeUnit; * @see ReadTimeoutHandler * @see WriteTimeoutHandler */ -public class IdleStateHandler extends ChannelStateHandlerAdapter implements ChannelOperationHandler { +public class IdleStateHandler extends ChannelInboundHandlerAdapter implements ChannelOutboundHandler { private final long readerIdleTimeMillis; private final long writerIdleTimeMillis; @@ -251,10 +251,10 @@ public class IdleStateHandler extends ChannelStateHandlerAdapter implements Chan } @Override - public void inboundBufferUpdated(ChannelHandlerContext ctx) throws Exception { + public void messageReceived(ChannelHandlerContext ctx, MessageList msgs) throws Exception { lastReadTime = System.currentTimeMillis(); firstReaderIdleEvent = firstAllIdleEvent = true; - ctx.fireInboundBufferUpdated(); + ctx.fireMessageReceived(msgs); } @Override @@ -263,8 +263,7 @@ public class IdleStateHandler extends ChannelStateHandlerAdapter implements Chan } @Override - - public void flush(final ChannelHandlerContext ctx, ChannelPromise promise) throws Exception { + public void write(ChannelHandlerContext ctx, MessageList msgs, ChannelPromise promise) throws Exception { promise.addListener(new ChannelFutureListener() { @Override public void operationComplete(ChannelFuture future) throws Exception { @@ -272,8 +271,7 @@ public class IdleStateHandler extends ChannelStateHandlerAdapter implements Chan firstWriterIdleEvent = firstAllIdleEvent = true; } }); - - ctx.flush(promise); + ctx.write(msgs, promise); } @Override @@ -302,18 +300,6 @@ public class IdleStateHandler extends ChannelStateHandlerAdapter implements Chan ctx.deregister(promise); } - @Override - public void sendFile(ChannelHandlerContext ctx, FileRegion region, ChannelPromise promise) throws Exception { - promise.addListener(new ChannelFutureListener() { - @Override - public void operationComplete(ChannelFuture future) throws Exception { - lastWriteTime = System.currentTimeMillis(); - firstWriterIdleEvent = firstAllIdleEvent = true; - } - }); - ctx.sendFile(region, promise); - } - private void initialize(ChannelHandlerContext ctx) { // Avoid the case where destroy() is called before scheduling timeouts. // See: https://github.com/netty/netty/issues/143 diff --git a/handler/src/main/java/io/netty/handler/timeout/ReadTimeoutHandler.java b/handler/src/main/java/io/netty/handler/timeout/ReadTimeoutHandler.java index 687445163e..0327906107 100644 --- a/handler/src/main/java/io/netty/handler/timeout/ReadTimeoutHandler.java +++ b/handler/src/main/java/io/netty/handler/timeout/ReadTimeoutHandler.java @@ -19,8 +19,9 @@ import io.netty.bootstrap.ServerBootstrap; import io.netty.channel.Channel; import io.netty.channel.ChannelDuplexHandler; import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.ChannelInboundHandlerAdapter; import io.netty.channel.ChannelInitializer; -import io.netty.channel.ChannelStateHandlerAdapter; +import io.netty.channel.MessageList; import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; @@ -61,7 +62,7 @@ import java.util.concurrent.TimeUnit; * @see WriteTimeoutHandler * @see IdleStateHandler */ -public class ReadTimeoutHandler extends ChannelStateHandlerAdapter { +public class ReadTimeoutHandler extends ChannelInboundHandlerAdapter { private final long timeoutMillis; @@ -144,9 +145,9 @@ public class ReadTimeoutHandler extends ChannelStateHandlerAdapter { } @Override - public void inboundBufferUpdated(ChannelHandlerContext ctx) throws Exception { + public void messageReceived(ChannelHandlerContext ctx, MessageList msgs) throws Exception { lastReadTime = System.currentTimeMillis(); - ctx.fireInboundBufferUpdated(); + ctx.fireMessageReceived(msgs); } private void initialize(ChannelHandlerContext ctx) { diff --git a/handler/src/main/java/io/netty/handler/timeout/WriteTimeoutHandler.java b/handler/src/main/java/io/netty/handler/timeout/WriteTimeoutHandler.java index a43d12feae..c5f85f03be 100644 --- a/handler/src/main/java/io/netty/handler/timeout/WriteTimeoutHandler.java +++ b/handler/src/main/java/io/netty/handler/timeout/WriteTimeoutHandler.java @@ -22,9 +22,9 @@ import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelFutureListener; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelInitializer; -import io.netty.channel.ChannelOperationHandlerAdapter; +import io.netty.channel.ChannelOutboundHandlerAdapter; import io.netty.channel.ChannelPromise; -import io.netty.channel.FileRegion; +import io.netty.channel.MessageList; import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; @@ -65,7 +65,7 @@ import java.util.concurrent.TimeUnit; * @see ReadTimeoutHandler * @see IdleStateHandler */ -public class WriteTimeoutHandler extends ChannelOperationHandlerAdapter { +public class WriteTimeoutHandler extends ChannelOutboundHandlerAdapter { private final long timeoutMillis; @@ -102,15 +102,9 @@ public class WriteTimeoutHandler extends ChannelOperationHandlerAdapter { } @Override - public void flush(final ChannelHandlerContext ctx, final ChannelPromise promise) throws Exception { + public void write(ChannelHandlerContext ctx, MessageList msgs, ChannelPromise promise) throws Exception { scheduleTimeout(ctx, promise); - ctx.flush(promise); - } - - @Override - public void sendFile(ChannelHandlerContext ctx, FileRegion region, ChannelPromise promise) throws Exception { - scheduleTimeout(ctx, promise); - super.sendFile(ctx, region, promise); + super.write(ctx, msgs, promise); } private void scheduleTimeout(final ChannelHandlerContext ctx, final ChannelPromise future) { diff --git a/handler/src/main/java/io/netty/handler/traffic/AbstractTrafficShapingHandler.java b/handler/src/main/java/io/netty/handler/traffic/AbstractTrafficShapingHandler.java index 1166c407a5..8723bd8e3d 100644 --- a/handler/src/main/java/io/netty/handler/traffic/AbstractTrafficShapingHandler.java +++ b/handler/src/main/java/io/netty/handler/traffic/AbstractTrafficShapingHandler.java @@ -19,6 +19,7 @@ import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelDuplexHandler; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelPromise; +import io.netty.channel.MessageList; import io.netty.util.Attribute; import io.netty.util.AttributeKey; @@ -74,7 +75,6 @@ public abstract class AbstractTrafficShapingHandler extends ChannelDuplexHandler private static final AttributeKey READ_SUSPENDED = new AttributeKey("readSuspended"); private static final AttributeKey REOPEN_TASK = new AttributeKey("reopenTask"); - private static final AttributeKey BUFFER_UPDATE_TASK = new AttributeKey("bufferUpdateTask"); /** * @@ -210,25 +210,27 @@ public abstract class AbstractTrafficShapingHandler extends ChannelDuplexHandler } @Override - public void inboundBufferUpdated(final ChannelHandlerContext ctx) throws Exception { - ByteBuf buf = ctx.nextInboundByteBuffer(); - + public void messageReceived(final ChannelHandlerContext ctx, final MessageList msgs) throws Exception { + MessageList buffers = msgs.cast(); + long size = 0; + for (int i = 0; i < buffers.size(); i++) { + size += buffers.get(i).readableBytes(); + } long curtime = System.currentTimeMillis(); - long size = buf.readableBytes(); if (trafficCounter != null) { trafficCounter.bytesRecvFlowControl(size); if (readLimit == 0) { // no action - ctx.fireInboundBufferUpdated(); + ctx.fireMessageReceived(msgs); return; } // compute the number of ms to wait before reopening the channel long wait = getTimeToWait(readLimit, - trafficCounter.currentReadBytes(), - trafficCounter.lastTime(), curtime); + trafficCounter.currentReadBytes(), + trafficCounter.lastTime(), curtime); if (wait >= MINIMAL_WAIT) { // At least 10ms seems a minimal // time in order to // try to limit the traffic @@ -244,27 +246,22 @@ public abstract class AbstractTrafficShapingHandler extends ChannelDuplexHandler attr.set(reopenTask); } ctx.executor().schedule(reopenTask, wait, - TimeUnit.MILLISECONDS); + TimeUnit.MILLISECONDS); } else { // Create a Runnable to update the next handler in the chain. If one was create before it will // just be reused to limit object creation - Attribute attr = ctx.attr(BUFFER_UPDATE_TASK); - Runnable bufferUpdateTask = attr.get(); - if (bufferUpdateTask == null) { - bufferUpdateTask = new Runnable() { - @Override - public void run() { - ctx.fireInboundBufferUpdated(); - } - }; - attr.set(bufferUpdateTask); - } + Runnable bufferUpdateTask = new Runnable() { + @Override + public void run() { + ctx.fireMessageReceived(msgs); + } + }; ctx.executor().schedule(bufferUpdateTask, wait, TimeUnit.MILLISECONDS); return; } } } - ctx.fireInboundBufferUpdated(); + ctx.fireMessageReceived(msgs); } @Override @@ -275,14 +272,18 @@ public abstract class AbstractTrafficShapingHandler extends ChannelDuplexHandler } @Override - public void flush(final ChannelHandlerContext ctx, final ChannelPromise promise) throws Exception { + public void write(final ChannelHandlerContext ctx, final MessageList msgs, final ChannelPromise promise) + throws Exception { long curtime = System.currentTimeMillis(); - long size = ctx.nextOutboundByteBuffer().readableBytes(); + long size = 0; + for (int i = 0; i < msgs.size(); i++) { + size += ((ByteBuf) msgs.get(i)).readableBytes(); + } if (trafficCounter != null) { trafficCounter.bytesWriteFlowControl(size); if (writeLimit == 0) { - ctx.flush(promise); + ctx.write(msgs, promise); return; } // compute the number of ms to wait before continue with the @@ -294,13 +295,13 @@ public abstract class AbstractTrafficShapingHandler extends ChannelDuplexHandler ctx.executor().schedule(new Runnable() { @Override public void run() { - ctx.flush(promise); + ctx.write(msgs, promise); } }, wait, TimeUnit.MILLISECONDS); return; } } - ctx.flush(promise); + ctx.write(msgs, promise); } /** diff --git a/handler/src/test/java/io/netty/handler/stream/ChunkedWriteHandlerTest.java b/handler/src/test/java/io/netty/handler/stream/ChunkedWriteHandlerTest.java index 99990f7231..6c5fef1c87 100644 --- a/handler/src/test/java/io/netty/handler/stream/ChunkedWriteHandlerTest.java +++ b/handler/src/test/java/io/netty/handler/stream/ChunkedWriteHandlerTest.java @@ -16,12 +16,11 @@ package io.netty.handler.stream; import io.netty.buffer.ByteBuf; -import io.netty.buffer.MessageBuf; import io.netty.buffer.Unpooled; import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelFutureListener; -import io.netty.channel.embedded.EmbeddedByteChannel; -import io.netty.channel.embedded.EmbeddedMessageChannel; +import io.netty.channel.MessageList; +import io.netty.channel.embedded.EmbeddedChannel; import io.netty.util.CharsetUtil; import org.junit.Test; import java.io.ByteArrayInputStream; @@ -135,9 +134,8 @@ public class ChunkedWriteHandlerTest { } }; - EmbeddedByteChannel ch = new EmbeddedByteChannel(new ChunkedWriteHandler()); - ch.outboundMessageBuffer().add(input); - ch.flush().addListener(listener).syncUninterruptibly(); + EmbeddedChannel ch = new EmbeddedChannel(new ChunkedWriteHandler()); + ch.write(input).addListener(listener).syncUninterruptibly(); ch.checkException(); ch.finish(); @@ -165,7 +163,7 @@ public class ChunkedWriteHandlerTest { } @Override - public boolean readChunk(MessageBuf buffer) throws Exception { + public boolean readChunk(MessageList buffer) throws Exception { if (done) { return false; } @@ -175,9 +173,8 @@ public class ChunkedWriteHandlerTest { } }; - EmbeddedMessageChannel ch = new EmbeddedMessageChannel(new ChunkedWriteHandler()); - ch.outboundMessageBuffer().add(input); - ch.flush().syncUninterruptibly(); + EmbeddedChannel ch = new EmbeddedChannel(new ChunkedWriteHandler()); + ch.write(input).syncUninterruptibly(); ch.checkException(); assertTrue(ch.finish()); @@ -186,7 +183,7 @@ public class ChunkedWriteHandlerTest { } private static void check(ChunkedInput... inputs) { - EmbeddedByteChannel ch = new EmbeddedByteChannel(new ChunkedWriteHandler()); + EmbeddedChannel ch = new EmbeddedChannel(new ChunkedWriteHandler()); for (ChunkedInput input: inputs) { ch.writeOutbound(input); @@ -197,7 +194,7 @@ public class ChunkedWriteHandlerTest { int i = 0; int read = 0; for (;;) { - ByteBuf buffer = ch.readOutbound(); + ByteBuf buffer = (ByteBuf) ch.readOutbound(); if (buffer == null) { break; } diff --git a/microbench/pom.xml b/microbench/pom.xml index c54d7265cb..c6633a024f 100644 --- a/microbench/pom.xml +++ b/microbench/pom.xml @@ -20,7 +20,7 @@ io.netty netty-parent - 4.0.0.Final-SNAPSHOT + 4.0.0.CR4-SNAPSHOT netty-microbench diff --git a/pom.xml b/pom.xml index b92e8acdb5..505d26232d 100644 --- a/pom.xml +++ b/pom.xml @@ -26,7 +26,7 @@ io.netty netty-parent pom - 4.0.0.Final-SNAPSHOT + 4.0.0.CR4-SNAPSHOT Netty http://netty.io/ diff --git a/tarball/pom.xml b/tarball/pom.xml index 47fb068a57..5af86caa5e 100644 --- a/tarball/pom.xml +++ b/tarball/pom.xml @@ -20,7 +20,7 @@ io.netty netty-parent - 4.0.0.Final-SNAPSHOT + 4.0.0.CR4-SNAPSHOT netty-tarball diff --git a/testsuite-osgi/pom.xml b/testsuite-osgi/pom.xml index 38a41def77..d3c487768e 100644 --- a/testsuite-osgi/pom.xml +++ b/testsuite-osgi/pom.xml @@ -21,7 +21,7 @@ io.netty netty-parent - 4.0.0.Final-SNAPSHOT + 4.0.0.CR4-SNAPSHOT netty-testsuite-osgi-parent diff --git a/testsuite-osgi/testsuite-osgi-deps/pom.xml b/testsuite-osgi/testsuite-osgi-deps/pom.xml index 66e804e552..0bbde8a045 100644 --- a/testsuite-osgi/testsuite-osgi-deps/pom.xml +++ b/testsuite-osgi/testsuite-osgi-deps/pom.xml @@ -21,7 +21,7 @@ io.netty netty-testsuite-osgi-parent - 4.0.0.Final-SNAPSHOT + 4.0.0.CR4-SNAPSHOT netty-testsuite-osgi-deps diff --git a/testsuite-osgi/testsuite-osgi-exam/pom.xml b/testsuite-osgi/testsuite-osgi-exam/pom.xml index 00b89b960f..26493c10dc 100644 --- a/testsuite-osgi/testsuite-osgi-exam/pom.xml +++ b/testsuite-osgi/testsuite-osgi-exam/pom.xml @@ -21,7 +21,7 @@ io.netty netty-testsuite-osgi-parent - 4.0.0.Final-SNAPSHOT + 4.0.0.CR4-SNAPSHOT netty-testsuite-osgi-exam diff --git a/testsuite-osgi/testsuite-osgi-split/pom.xml b/testsuite-osgi/testsuite-osgi-split/pom.xml index ee743e3f54..0a752e7c3b 100644 --- a/testsuite-osgi/testsuite-osgi-split/pom.xml +++ b/testsuite-osgi/testsuite-osgi-split/pom.xml @@ -21,7 +21,7 @@ io.netty netty-testsuite-osgi-parent - 4.0.0.Final-SNAPSHOT + 4.0.0.CR4-SNAPSHOT netty-testsuite-osgi-split diff --git a/testsuite/pom.xml b/testsuite/pom.xml index 12caa73f17..76f3dbf5e5 100644 --- a/testsuite/pom.xml +++ b/testsuite/pom.xml @@ -20,7 +20,7 @@ io.netty netty-parent - 4.0.0.Final-SNAPSHOT + 4.0.0.CR4-SNAPSHOT netty-testsuite diff --git a/testsuite/src/test/java/io/netty/testsuite/transport/sctp/SctpEchoTest.java b/testsuite/src/test/java/io/netty/testsuite/transport/sctp/SctpEchoTest.java index 62fecd7efe..dd15f1df7e 100644 --- a/testsuite/src/test/java/io/netty/testsuite/transport/sctp/SctpEchoTest.java +++ b/testsuite/src/test/java/io/netty/testsuite/transport/sctp/SctpEchoTest.java @@ -21,9 +21,9 @@ import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import io.netty.channel.Channel; import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.ChannelHandlerUtil; -import io.netty.channel.ChannelInboundByteHandlerAdapter; +import io.netty.channel.ChannelInboundHandlerAdapter; import io.netty.channel.ChannelInitializer; +import io.netty.channel.MessageList; import io.netty.channel.sctp.SctpChannel; import io.netty.handler.codec.sctp.SctpInboundByteStreamHandler; import io.netty.handler.codec.sctp.SctpMessageCompletionHandler; @@ -54,22 +54,12 @@ public class SctpEchoTest extends AbstractSctpTest { } public void testSimpleEcho(ServerBootstrap sb, Bootstrap cb) throws Throwable { - testSimpleEcho0(sb, cb, Integer.MAX_VALUE); + testSimpleEcho0(sb, cb); } - @Test - public void testSimpleEchoWithBoundedBuffer() throws Throwable { - Assume.assumeTrue(TestUtils.isSctpSupported()); - run(); - } - - public void testSimpleEchoWithBoundedBuffer(ServerBootstrap sb, Bootstrap cb) throws Throwable { - testSimpleEcho0(sb, cb, 4096); - } - - private static void testSimpleEcho0(ServerBootstrap sb, Bootstrap cb, int maxInboundBufferSize) throws Throwable { - final EchoHandler sh = new EchoHandler(maxInboundBufferSize); - final EchoHandler ch = new EchoHandler(maxInboundBufferSize); + private static void testSimpleEcho0(ServerBootstrap sb, Bootstrap cb) throws Throwable { + final EchoHandler sh = new EchoHandler(); + final EchoHandler ch = new EchoHandler(); sb.childHandler(new ChannelInitializer() { @Override @@ -149,21 +139,11 @@ public class SctpEchoTest extends AbstractSctpTest { } } - private static class EchoHandler extends ChannelInboundByteHandlerAdapter { - private final int maxInboundBufferSize; + private static class EchoHandler extends ChannelInboundHandlerAdapter { volatile Channel channel; final AtomicReference exception = new AtomicReference(); volatile int counter; - EchoHandler(int maxInboundBufferSize) { - this.maxInboundBufferSize = maxInboundBufferSize; - } - - @Override - public ByteBuf newInboundBuffer(ChannelHandlerContext ctx) throws Exception { - return ChannelHandlerUtil.allocate(ctx, 0, maxInboundBufferSize); - } - @Override public void channelActive(ChannelHandlerContext ctx) throws Exception { @@ -171,22 +151,23 @@ public class SctpEchoTest extends AbstractSctpTest { } @Override - public void inboundBufferUpdated( - ChannelHandlerContext ctx, ByteBuf in) - throws Exception { - byte[] actual = new byte[in.readableBytes()]; - in.readBytes(actual); + public void messageReceived(ChannelHandlerContext ctx, MessageList msgs) throws Exception { + for (int j = 0; j < msgs.size(); j ++) { + ByteBuf in = (ByteBuf) msgs.get(j); + byte[] actual = new byte[in.readableBytes()]; + in.readBytes(actual); - int lastIdx = counter; - for (int i = 0; i < actual.length; i++) { - assertEquals(data[i + lastIdx], actual[i]); + int lastIdx = counter; + for (int i = 0; i < actual.length; i++) { + assertEquals(data[i + lastIdx], actual[i]); + } + + if (channel.parent() != null) { + channel.write(Unpooled.wrappedBuffer(actual)); + } + + counter += actual.length; } - - if (channel.parent() != null) { - channel.write(Unpooled.wrappedBuffer(actual)); - } - - counter += actual.length; } @Override diff --git a/testsuite/src/test/java/io/netty/testsuite/transport/socket/DatagramMulticastTest.java b/testsuite/src/test/java/io/netty/testsuite/transport/socket/DatagramMulticastTest.java index a62104781e..5a59cc8615 100644 --- a/testsuite/src/test/java/io/netty/testsuite/transport/socket/DatagramMulticastTest.java +++ b/testsuite/src/test/java/io/netty/testsuite/transport/socket/DatagramMulticastTest.java @@ -19,8 +19,9 @@ import io.netty.bootstrap.Bootstrap; import io.netty.buffer.Unpooled; import io.netty.channel.Channel; import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.ChannelInboundMessageHandlerAdapter; +import io.netty.channel.ChannelInboundHandlerAdapter; import io.netty.channel.ChannelOption; +import io.netty.channel.MessageList; import io.netty.channel.socket.DatagramChannel; import io.netty.channel.socket.DatagramPacket; import io.netty.channel.socket.oio.OioDatagramChannel; @@ -43,12 +44,11 @@ public class DatagramMulticastTest extends AbstractDatagramTest { public void testMulticast(Bootstrap sb, Bootstrap cb) throws Throwable { MulticastTestHandler mhandler = new MulticastTestHandler(); - sb.handler(new ChannelInboundMessageHandlerAdapter() { + sb.handler(new ChannelInboundHandlerAdapter() { @Override - public void messageReceived( - ChannelHandlerContext ctx, - DatagramPacket msg) throws Exception { + public void messageReceived(ChannelHandlerContext ctx, MessageList msgs) throws Exception { // Nothing will be sent. + msgs.releaseAllAndRecycle(); } }); @@ -92,19 +92,21 @@ public class DatagramMulticastTest extends AbstractDatagramTest { cc.close().awaitUninterruptibly(); } - private static final class MulticastTestHandler extends ChannelInboundMessageHandlerAdapter { + private static final class MulticastTestHandler extends ChannelInboundHandlerAdapter { private final CountDownLatch latch = new CountDownLatch(1); private boolean done; private volatile boolean fail; @Override - public void messageReceived(ChannelHandlerContext ctx, DatagramPacket msg) throws Exception { - if (done) { + public void messageReceived(ChannelHandlerContext ctx, MessageList msgs) throws Exception { + if (done || msgs.size() != 1) { fail = true; } - assertEquals(1, msg.content().readInt()); + assertEquals(1, ((DatagramPacket) msgs.get(0)).content().readInt()); + msgs.releaseAllAndRecycle(); + latch.countDown(); // mark the handler as done as we only are supposed to receive one message diff --git a/testsuite/src/test/java/io/netty/testsuite/transport/socket/DatagramUnicastTest.java b/testsuite/src/test/java/io/netty/testsuite/transport/socket/DatagramUnicastTest.java index 9e1237e960..4ad4c9320b 100644 --- a/testsuite/src/test/java/io/netty/testsuite/transport/socket/DatagramUnicastTest.java +++ b/testsuite/src/test/java/io/netty/testsuite/transport/socket/DatagramUnicastTest.java @@ -19,7 +19,8 @@ import io.netty.bootstrap.Bootstrap; import io.netty.buffer.Unpooled; import io.netty.channel.Channel; import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.ChannelInboundMessageHandlerAdapter; +import io.netty.channel.ChannelInboundHandlerAdapter; +import io.netty.channel.MessageList; import io.netty.channel.socket.DatagramPacket; import org.junit.Test; @@ -38,22 +39,21 @@ public class DatagramUnicastTest extends AbstractDatagramTest { public void testSimpleSend(Bootstrap sb, Bootstrap cb) throws Throwable { final CountDownLatch latch = new CountDownLatch(1); - sb.handler(new ChannelInboundMessageHandlerAdapter() { + sb.handler(new ChannelInboundHandlerAdapter() { @Override - public void messageReceived( - ChannelHandlerContext ctx, - DatagramPacket msg) throws Exception { - assertEquals(1, msg.content().readInt()); + public void messageReceived(ChannelHandlerContext ctx, MessageList msgs) throws Exception { + assertEquals(1, msgs.size()); + assertEquals(1, ((DatagramPacket) msgs.get(0)).content().readInt()); + msgs.releaseAllAndRecycle(); latch.countDown(); } }); - cb.handler(new ChannelInboundMessageHandlerAdapter() { + cb.handler(new ChannelInboundHandlerAdapter() { @Override - public void messageReceived( - ChannelHandlerContext ctx, - DatagramPacket msg) throws Exception { + public void messageReceived(ChannelHandlerContext ctx, MessageList msgs) throws Exception { // Nothing will be sent. + msgs.releaseAllAndRecycle(); } }); diff --git a/testsuite/src/test/java/io/netty/testsuite/transport/socket/ServerSocketSuspendTest.java b/testsuite/src/test/java/io/netty/testsuite/transport/socket/ServerSocketSuspendTest.java index 726a97c8a0..af3fe50a72 100644 --- a/testsuite/src/test/java/io/netty/testsuite/transport/socket/ServerSocketSuspendTest.java +++ b/testsuite/src/test/java/io/netty/testsuite/transport/socket/ServerSocketSuspendTest.java @@ -16,11 +16,10 @@ package io.netty.testsuite.transport.socket; import io.netty.bootstrap.ServerBootstrap; -import io.netty.buffer.ByteBuf; import io.netty.channel.Channel; import io.netty.channel.ChannelHandler; import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.ChannelInboundByteHandlerAdapter; +import io.netty.channel.ChannelInboundHandlerAdapter; import io.netty.channel.ChannelOption; import org.junit.Ignore; import org.junit.Test; @@ -94,7 +93,7 @@ public class ServerSocketSuspendTest extends AbstractServerSocketTest { } @ChannelHandler.Sharable - private static final class AcceptedChannelCounter extends ChannelInboundByteHandlerAdapter { + private static final class AcceptedChannelCounter extends ChannelInboundHandlerAdapter { final CountDownLatch latch; @@ -106,10 +105,5 @@ public class ServerSocketSuspendTest extends AbstractServerSocketTest { public void channelActive(ChannelHandlerContext ctx) throws Exception { latch.countDown(); } - - @Override - public void inboundBufferUpdated(ChannelHandlerContext ctx, ByteBuf in) throws Exception { - // Unused - } } } diff --git a/testsuite/src/test/java/io/netty/testsuite/transport/socket/SocketBufReleaseTest.java b/testsuite/src/test/java/io/netty/testsuite/transport/socket/SocketBufReleaseTest.java index fb16050f16..ae02ab802d 100644 --- a/testsuite/src/test/java/io/netty/testsuite/transport/socket/SocketBufReleaseTest.java +++ b/testsuite/src/test/java/io/netty/testsuite/transport/socket/SocketBufReleaseTest.java @@ -22,7 +22,8 @@ import io.netty.channel.Channel; import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelFutureListener; import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.ChannelInboundMessageHandlerAdapter; +import io.netty.channel.ChannelInboundHandlerAdapter; +import io.netty.channel.MessageList; import io.netty.util.concurrent.DefaultEventExecutorGroup; import io.netty.util.concurrent.DefaultPromise; import io.netty.util.concurrent.DefaultThreadFactory; @@ -66,7 +67,7 @@ public class SocketBufReleaseTest extends AbstractSocketTest { clientHandler.check(); } - private static class BufWriterHandler extends ChannelInboundMessageHandlerAdapter { + private static class BufWriterHandler extends ChannelInboundHandlerAdapter { private final Random random = new Random(); private final CountDownLatch latch = new CountDownLatch(1); @@ -95,8 +96,8 @@ public class SocketBufReleaseTest extends AbstractSocketTest { } @Override - public void messageReceived(ChannelHandlerContext ctx, Object msg) throws Exception { - // Discard + public void messageReceived(ChannelHandlerContext ctx, MessageList msgs) throws Exception { + msgs.releaseAllAndRecycle(); } public void check() throws InterruptedException { diff --git a/testsuite/src/test/java/io/netty/testsuite/transport/socket/SocketEchoTest.java b/testsuite/src/test/java/io/netty/testsuite/transport/socket/SocketEchoTest.java index 35b4ec84bd..2d3e2f9e94 100644 --- a/testsuite/src/test/java/io/netty/testsuite/transport/socket/SocketEchoTest.java +++ b/testsuite/src/test/java/io/netty/testsuite/transport/socket/SocketEchoTest.java @@ -21,9 +21,9 @@ import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import io.netty.channel.Channel; import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.ChannelHandlerUtil; -import io.netty.channel.ChannelInboundByteHandlerAdapter; +import io.netty.channel.ChannelInboundHandlerAdapter; import io.netty.channel.ChannelInitializer; +import io.netty.channel.MessageList; import io.netty.channel.socket.SocketChannel; import io.netty.util.concurrent.DefaultEventExecutorGroup; import io.netty.util.concurrent.EventExecutorGroup; @@ -64,34 +64,16 @@ public class SocketEchoTest extends AbstractSocketTest { } public void testSimpleEcho(ServerBootstrap sb, Bootstrap cb) throws Throwable { - testSimpleEcho0(sb, cb, Integer.MAX_VALUE, false, false); + testSimpleEcho0(sb, cb, false, false); } @Test(timeout = 30000) - public void testSimpleEchoWithBridge() throws Throwable { + public void testSimpleEchoWithAdditionalExecutor() throws Throwable { run(); } - public void testSimpleEchoWithBridge(ServerBootstrap sb, Bootstrap cb) throws Throwable { - testSimpleEcho0(sb, cb, Integer.MAX_VALUE, true, false); - } - - @Test(timeout = 30000) - public void testSimpleEchoWithBoundedBuffer() throws Throwable { - run(); - } - - public void testSimpleEchoWithBoundedBuffer(ServerBootstrap sb, Bootstrap cb) throws Throwable { - testSimpleEcho0(sb, cb, 32, false, false); - } - - @Test(timeout = 30000) - public void testSimpleEchoWithBridgedBoundedBuffer() throws Throwable { - run(); - } - - public void testSimpleEchoWithBridgedBoundedBuffer(ServerBootstrap sb, Bootstrap cb) throws Throwable { - testSimpleEcho0(sb, cb, 32, true, false); + public void testSimpleEchoWithAdditionalExecutor(ServerBootstrap sb, Bootstrap cb) throws Throwable { + testSimpleEcho0(sb, cb, true, false); } @Test(timeout = 30000) @@ -100,26 +82,26 @@ public class SocketEchoTest extends AbstractSocketTest { } public void testSimpleEchoWithVoidPromise(ServerBootstrap sb, Bootstrap cb) throws Throwable { - testSimpleEcho0(sb, cb, Integer.MAX_VALUE, false, true); + testSimpleEcho0(sb, cb, false, true); } @Test(timeout = 30000) - public void testSimpleEchoWithBridgeAndVoidPromise() throws Throwable { + public void testSimpleEchoWithAdditionalExecutorAndVoidPromise() throws Throwable { run(); } - public void testSimpleEchoWithBridgeAndVoidPromise(ServerBootstrap sb, Bootstrap cb) throws Throwable { - testSimpleEcho0(sb, cb, Integer.MAX_VALUE, true, true); + public void testSimpleEchoWithAdditionalExecutorAndVoidPromise(ServerBootstrap sb, Bootstrap cb) throws Throwable { + testSimpleEcho0(sb, cb, true, true); } private static void testSimpleEcho0( - ServerBootstrap sb, Bootstrap cb, int maxInboundBufferSize, boolean bridge, boolean voidPromise) + ServerBootstrap sb, Bootstrap cb, boolean additionalExecutor, boolean voidPromise) throws Throwable { - final EchoHandler sh = new EchoHandler(maxInboundBufferSize); - final EchoHandler ch = new EchoHandler(maxInboundBufferSize); + final EchoHandler sh = new EchoHandler(); + final EchoHandler ch = new EchoHandler(); - if (bridge) { + if (additionalExecutor) { sb.childHandler(new ChannelInitializer() { @Override protected void initChannel(SocketChannel c) throws Exception { @@ -199,21 +181,11 @@ public class SocketEchoTest extends AbstractSocketTest { } } - private static class EchoHandler extends ChannelInboundByteHandlerAdapter { - private final int maxInboundBufferSize; + private static class EchoHandler extends ChannelInboundHandlerAdapter { volatile Channel channel; final AtomicReference exception = new AtomicReference(); volatile int counter; - EchoHandler(int maxInboundBufferSize) { - this.maxInboundBufferSize = maxInboundBufferSize; - } - - @Override - public ByteBuf newInboundBuffer(ChannelHandlerContext ctx) throws Exception { - return ChannelHandlerUtil.allocate(ctx, 0, maxInboundBufferSize); - } - @Override public void channelActive(ChannelHandlerContext ctx) throws Exception { @@ -221,22 +193,24 @@ public class SocketEchoTest extends AbstractSocketTest { } @Override - public void inboundBufferUpdated( - ChannelHandlerContext ctx, ByteBuf in) - throws Exception { - byte[] actual = new byte[in.readableBytes()]; - in.readBytes(actual); + public void messageReceived(ChannelHandlerContext ctx, MessageList msgs) throws Exception { + for (int j = 0; j < msgs.size(); j ++) { + ByteBuf in = (ByteBuf) msgs.get(j); + byte[] actual = new byte[in.readableBytes()]; + in.readBytes(actual); - int lastIdx = counter; - for (int i = 0; i < actual.length; i ++) { - assertEquals(data[i + lastIdx], actual[i]); + int lastIdx = counter; + for (int i = 0; i < actual.length; i ++) { + assertEquals(data[i + lastIdx], actual[i]); + } + + if (channel.parent() != null) { + channel.write(Unpooled.wrappedBuffer(actual)); + } + + counter += actual.length; } - - if (channel.parent() != null) { - channel.write(Unpooled.wrappedBuffer(actual)); - } - - counter += actual.length; + msgs.releaseAllAndRecycle(); } @Override diff --git a/testsuite/src/test/java/io/netty/testsuite/transport/socket/SocketFileRegionTest.java b/testsuite/src/test/java/io/netty/testsuite/transport/socket/SocketFileRegionTest.java index 0a002c30ba..7d52878508 100644 --- a/testsuite/src/test/java/io/netty/testsuite/transport/socket/SocketFileRegionTest.java +++ b/testsuite/src/test/java/io/netty/testsuite/transport/socket/SocketFileRegionTest.java @@ -20,9 +20,11 @@ import io.netty.bootstrap.ServerBootstrap; import io.netty.buffer.ByteBuf; import io.netty.channel.Channel; import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.ChannelInboundByteHandlerAdapter; +import io.netty.channel.ChannelInboundHandler; +import io.netty.channel.ChannelInboundHandlerAdapter; import io.netty.channel.DefaultFileRegion; import io.netty.channel.FileRegion; +import io.netty.channel.MessageList; import org.junit.Test; import java.io.File; @@ -69,10 +71,12 @@ public class SocketFileRegionTest extends AbstractSocketTest { out.write(data); out.close(); - ChannelInboundByteHandlerAdapter ch = new ChannelInboundByteHandlerAdapter() { + ChannelInboundHandler ch = new ChannelInboundHandlerAdapter() { + @Override - public void inboundBufferUpdated(ChannelHandlerContext ctx, ByteBuf in) throws Exception { - in.clear(); + public void messageReceived(ChannelHandlerContext ctx, MessageList msgs) throws Exception { + // discard + msgs.releaseAllAndRecycle(); } @Override @@ -88,12 +92,11 @@ public class SocketFileRegionTest extends AbstractSocketTest { Channel sc = sb.bind().sync().channel(); Channel cc = cb.connect().sync().channel(); - FileRegion region = new DefaultFileRegion(new FileInputStream(file).getChannel(), - 0L, file.length()); + FileRegion region = new DefaultFileRegion(new FileInputStream(file).getChannel(), 0L, file.length()); if (voidPromise) { - assertEquals(cc.voidPromise(), cc.sendFile(region, cc.voidPromise())); + assertEquals(cc.voidPromise(), cc.write(region, cc.voidPromise())); } else { - assertNotEquals(cc.voidPromise(), cc.sendFile(region)); + assertNotEquals(cc.voidPromise(), cc.write(region)); } while (sh.counter < data.length) { if (sh.exception.get() != null) { @@ -120,7 +123,7 @@ public class SocketFileRegionTest extends AbstractSocketTest { } } - private static class TestHandler extends ChannelInboundByteHandlerAdapter { + private static class TestHandler extends ChannelInboundHandlerAdapter { volatile Channel channel; final AtomicReference exception = new AtomicReference(); volatile int counter; @@ -132,17 +135,19 @@ public class SocketFileRegionTest extends AbstractSocketTest { } @Override - public void inboundBufferUpdated( - ChannelHandlerContext ctx, ByteBuf in) - throws Exception { - byte[] actual = new byte[in.readableBytes()]; - in.readBytes(actual); + public void messageReceived(ChannelHandlerContext ctx, MessageList msgs) throws Exception { + for (int j = 0; j < msgs.size(); j ++) { + ByteBuf in = (ByteBuf) msgs.get(j); + byte[] actual = new byte[in.readableBytes()]; + in.readBytes(actual); - int lastIdx = counter; - for (int i = 0; i < actual.length; i ++) { - assertEquals(data[i + lastIdx], actual[i]); + int lastIdx = counter; + for (int i = 0; i < actual.length; i ++) { + assertEquals(data[i + lastIdx], actual[i]); + } + counter += actual.length; } - counter += actual.length; + msgs.releaseAllAndRecycle(); } @Override diff --git a/testsuite/src/test/java/io/netty/testsuite/transport/socket/SocketFixedLengthEchoTest.java b/testsuite/src/test/java/io/netty/testsuite/transport/socket/SocketFixedLengthEchoTest.java index 206406dd09..d25528fcf0 100644 --- a/testsuite/src/test/java/io/netty/testsuite/transport/socket/SocketFixedLengthEchoTest.java +++ b/testsuite/src/test/java/io/netty/testsuite/transport/socket/SocketFixedLengthEchoTest.java @@ -21,8 +21,9 @@ import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import io.netty.channel.Channel; import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.ChannelInboundMessageHandlerAdapter; +import io.netty.channel.ChannelInboundHandlerAdapter; import io.netty.channel.ChannelInitializer; +import io.netty.channel.MessageList; import io.netty.channel.socket.SocketChannel; import io.netty.handler.codec.FixedLengthFrameDecoder; import org.junit.Test; @@ -123,7 +124,7 @@ public class SocketFixedLengthEchoTest extends AbstractSocketTest { } } - private static class EchoHandler extends ChannelInboundMessageHandlerAdapter { + private static class EchoHandler extends ChannelInboundHandlerAdapter { volatile Channel channel; final AtomicReference exception = new AtomicReference(); volatile int counter; @@ -135,24 +136,26 @@ public class SocketFixedLengthEchoTest extends AbstractSocketTest { } @Override - public void messageReceived( - ChannelHandlerContext ctx, - ByteBuf msg) throws Exception { - assertEquals(1024, msg.readableBytes()); + public void messageReceived(ChannelHandlerContext ctx, MessageList msgs) throws Exception { + for (int j = 0; j < msgs.size(); j ++) { + ByteBuf msg = (ByteBuf) msgs.get(j); + assertEquals(1024, msg.readableBytes()); - byte[] actual = new byte[msg.readableBytes()]; - msg.getBytes(0, actual); + byte[] actual = new byte[msg.readableBytes()]; + msg.getBytes(0, actual); - int lastIdx = counter; - for (int i = 0; i < actual.length; i ++) { - assertEquals(data[i + lastIdx], actual[i]); + int lastIdx = counter; + for (int i = 0; i < actual.length; i ++) { + assertEquals(data[i + lastIdx], actual[i]); + } + + if (channel.parent() != null) { + channel.write(msg.retain()); + } + + counter += actual.length; } - - if (channel.parent() != null) { - channel.write(msg.retain()); - } - - counter += actual.length; + msgs.releaseAllAndRecycle(); } @Override diff --git a/testsuite/src/test/java/io/netty/testsuite/transport/socket/SocketObjectEchoTest.java b/testsuite/src/test/java/io/netty/testsuite/transport/socket/SocketObjectEchoTest.java index d57abd2152..d660df2784 100644 --- a/testsuite/src/test/java/io/netty/testsuite/transport/socket/SocketObjectEchoTest.java +++ b/testsuite/src/test/java/io/netty/testsuite/transport/socket/SocketObjectEchoTest.java @@ -19,8 +19,9 @@ import io.netty.bootstrap.Bootstrap; import io.netty.bootstrap.ServerBootstrap; import io.netty.channel.Channel; import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.ChannelInboundMessageHandlerAdapter; +import io.netty.channel.ChannelInboundHandlerAdapter; import io.netty.channel.ChannelInitializer; +import io.netty.channel.MessageList; import io.netty.channel.socket.SocketChannel; import io.netty.handler.codec.serialization.ClassResolvers; import io.netty.handler.codec.serialization.ObjectDecoder; @@ -133,7 +134,7 @@ public class SocketObjectEchoTest extends AbstractSocketTest { } } - private static class EchoHandler extends ChannelInboundMessageHandlerAdapter { + private static class EchoHandler extends ChannelInboundHandlerAdapter { volatile Channel channel; final AtomicReference exception = new AtomicReference(); volatile int counter; @@ -148,15 +149,18 @@ public class SocketObjectEchoTest extends AbstractSocketTest { } @Override - public void messageReceived(ChannelHandlerContext ctx, - String msg) throws Exception { - assertEquals(data[counter], msg); + public void messageReceived(ChannelHandlerContext ctx, MessageList msgs) throws Exception { + for (int i = 0; i < msgs.size(); i ++) { + String msg = (String) msgs.get(i); + assertEquals(data[counter], msg); - if (channel.parent() != null) { - channel.write(msg); + if (channel.parent() != null) { + channel.write(msg); + } + + counter ++; } - - counter ++; + msgs.releaseAllAndRecycle(); } @Override diff --git a/testsuite/src/test/java/io/netty/testsuite/transport/socket/SocketShutdownOutputByPeerTest.java b/testsuite/src/test/java/io/netty/testsuite/transport/socket/SocketShutdownOutputByPeerTest.java index e5e6a4df04..f2b30237db 100644 --- a/testsuite/src/test/java/io/netty/testsuite/transport/socket/SocketShutdownOutputByPeerTest.java +++ b/testsuite/src/test/java/io/netty/testsuite/transport/socket/SocketShutdownOutputByPeerTest.java @@ -18,8 +18,9 @@ package io.netty.testsuite.transport.socket; import io.netty.bootstrap.ServerBootstrap; import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.ChannelInboundByteHandlerAdapter; +import io.netty.channel.ChannelInboundHandlerAdapter; import io.netty.channel.ChannelOption; +import io.netty.channel.MessageList; import io.netty.channel.socket.ChannelInputShutdownEvent; import io.netty.channel.socket.SocketChannel; import org.junit.Test; @@ -109,7 +110,7 @@ public class SocketShutdownOutputByPeerTest extends AbstractServerSocketTest { } } - private static class TestHandler extends ChannelInboundByteHandlerAdapter { + private static class TestHandler extends ChannelInboundHandlerAdapter { volatile SocketChannel ch; final BlockingQueue queue = new LinkedBlockingQueue(); final CountDownLatch halfClosure = new CountDownLatch(1); @@ -127,8 +128,11 @@ public class SocketShutdownOutputByPeerTest extends AbstractServerSocketTest { } @Override - public void inboundBufferUpdated(ChannelHandlerContext ctx, ByteBuf in) throws Exception { - queue.offer(in.readByte()); + public void messageReceived(ChannelHandlerContext ctx, MessageList msgs) throws Exception { + for (int i = 0; i < msgs.size(); i ++) { + queue.offer(((ByteBuf) msgs.get(i)).readByte()); + } + msgs.releaseAllAndRecycle(); } @Override diff --git a/testsuite/src/test/java/io/netty/testsuite/transport/socket/SocketShutdownOutputBySelfTest.java b/testsuite/src/test/java/io/netty/testsuite/transport/socket/SocketShutdownOutputBySelfTest.java index 5c377c31db..a895c6846e 100644 --- a/testsuite/src/test/java/io/netty/testsuite/transport/socket/SocketShutdownOutputBySelfTest.java +++ b/testsuite/src/test/java/io/netty/testsuite/transport/socket/SocketShutdownOutputBySelfTest.java @@ -19,7 +19,8 @@ import io.netty.bootstrap.Bootstrap; import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.ChannelInboundByteHandlerAdapter; +import io.netty.channel.ChannelInboundHandlerAdapter; +import io.netty.channel.MessageList; import io.netty.channel.socket.SocketChannel; import org.junit.Test; @@ -76,7 +77,7 @@ public class SocketShutdownOutputBySelfTest extends AbstractClientSocketTest { } } - private static class TestHandler extends ChannelInboundByteHandlerAdapter { + private static class TestHandler extends ChannelInboundHandlerAdapter { volatile SocketChannel ch; final BlockingQueue queue = new LinkedBlockingQueue(); @@ -86,8 +87,11 @@ public class SocketShutdownOutputBySelfTest extends AbstractClientSocketTest { } @Override - public void inboundBufferUpdated(ChannelHandlerContext ctx, ByteBuf in) throws Exception { - queue.offer(in.readByte()); + public void messageReceived(ChannelHandlerContext ctx, MessageList msgs) throws Exception { + for (int i = 0; i < msgs.size(); i ++) { + queue.offer(((ByteBuf) msgs.get(i)).readByte()); + } + msgs.releaseAllAndRecycle(); } } } diff --git a/testsuite/src/test/java/io/netty/testsuite/transport/socket/SocketSpdyEchoTest.java b/testsuite/src/test/java/io/netty/testsuite/transport/socket/SocketSpdyEchoTest.java index 905f315daa..19b15bfbcb 100644 --- a/testsuite/src/test/java/io/netty/testsuite/transport/socket/SocketSpdyEchoTest.java +++ b/testsuite/src/test/java/io/netty/testsuite/transport/socket/SocketSpdyEchoTest.java @@ -17,14 +17,13 @@ package io.netty.testsuite.transport.socket; import io.netty.bootstrap.Bootstrap; import io.netty.bootstrap.ServerBootstrap; -import io.netty.buffer.BufUtil; import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import io.netty.channel.Channel; import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.ChannelInboundByteHandlerAdapter; -import io.netty.channel.ChannelInboundMessageHandlerAdapter; +import io.netty.channel.ChannelInboundHandlerAdapter; import io.netty.channel.ChannelInitializer; +import io.netty.channel.MessageList; import io.netty.channel.socket.SocketChannel; import io.netty.handler.codec.spdy.SpdyConstants; import io.netty.handler.codec.spdy.SpdyFrameDecoder; @@ -230,13 +229,12 @@ public class SocketSpdyEchoTest extends AbstractSocketTest { } } - private static class SpdyEchoTestServerHandler extends ChannelInboundMessageHandlerAdapter { + private static class SpdyEchoTestServerHandler extends ChannelInboundHandlerAdapter { final AtomicReference exception = new AtomicReference(); @Override - public void messageReceived(ChannelHandlerContext ctx, Object msg) throws Exception { - BufUtil.retain(msg); - ctx.write(msg); + public void messageReceived(ChannelHandlerContext ctx, MessageList msgs) throws Exception { + ctx.write(msgs); } @Override @@ -247,7 +245,7 @@ public class SocketSpdyEchoTest extends AbstractSocketTest { } } - private static class SpdyEchoTestClientHandler extends ChannelInboundByteHandlerAdapter { + private static class SpdyEchoTestClientHandler extends ChannelInboundHandlerAdapter { final AtomicReference exception = new AtomicReference(); final ByteBuf frames; volatile int counter; @@ -257,16 +255,20 @@ public class SocketSpdyEchoTest extends AbstractSocketTest { } @Override - public void inboundBufferUpdated(ChannelHandlerContext ctx, ByteBuf in) throws Exception { - byte[] actual = new byte[in.readableBytes()]; - in.readBytes(actual); + public void messageReceived(ChannelHandlerContext ctx, MessageList msgs) throws Exception { + for (int j = 0; j < msgs.size(); j ++) { + ByteBuf in = (ByteBuf) msgs.get(j); + byte[] actual = new byte[in.readableBytes()]; + in.readBytes(actual); - int lastIdx = counter; - for (int i = 0; i < actual.length; i ++) { - assertEquals(frames.getByte(ignoredBytes + i + lastIdx), actual[i]); + int lastIdx = counter; + for (int i = 0; i < actual.length; i ++) { + assertEquals(frames.getByte(ignoredBytes + i + lastIdx), actual[i]); + } + + counter += actual.length; } - - counter += actual.length; + msgs.releaseAllAndRecycle(); } @Override diff --git a/testsuite/src/test/java/io/netty/testsuite/transport/socket/SocketSslEchoTest.java b/testsuite/src/test/java/io/netty/testsuite/transport/socket/SocketSslEchoTest.java index c90f6899e6..3e75430eda 100644 --- a/testsuite/src/test/java/io/netty/testsuite/transport/socket/SocketSslEchoTest.java +++ b/testsuite/src/test/java/io/netty/testsuite/transport/socket/SocketSslEchoTest.java @@ -15,30 +15,29 @@ */ package io.netty.testsuite.transport.socket; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; import io.netty.bootstrap.Bootstrap; import io.netty.bootstrap.ServerBootstrap; import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import io.netty.channel.Channel; import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.ChannelInboundByteHandlerAdapter; +import io.netty.channel.ChannelInboundHandlerAdapter; import io.netty.channel.ChannelInitializer; +import io.netty.channel.MessageList; import io.netty.channel.socket.SocketChannel; import io.netty.handler.ssl.SslHandler; import io.netty.handler.stream.ChunkedWriteHandler; import io.netty.testsuite.util.BogusSslContextFactory; import io.netty.util.concurrent.Future; +import org.junit.Test; +import javax.net.ssl.SSLEngine; import java.io.IOException; import java.util.Random; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicReference; -import javax.net.ssl.SSLEngine; - -import org.junit.Test; +import static org.junit.Assert.*; public class SocketSslEchoTest extends AbstractSocketTest { @@ -163,7 +162,7 @@ public class SocketSslEchoTest extends AbstractSocketTest { } } - private class EchoHandler extends ChannelInboundByteHandlerAdapter { + private class EchoHandler extends ChannelInboundHandlerAdapter { volatile Channel channel; final AtomicReference exception = new AtomicReference(); volatile int counter; @@ -180,22 +179,24 @@ public class SocketSslEchoTest extends AbstractSocketTest { } @Override - public void inboundBufferUpdated( - ChannelHandlerContext ctx, ByteBuf in) - throws Exception { - byte[] actual = new byte[in.readableBytes()]; - in.readBytes(actual); + public void messageReceived(ChannelHandlerContext ctx, MessageList msgs) throws Exception { + for (int j = 0; j < msgs.size(); j ++) { + ByteBuf in = (ByteBuf) msgs.get(j); + byte[] actual = new byte[in.readableBytes()]; + in.readBytes(actual); - int lastIdx = counter; - for (int i = 0; i < actual.length; i ++) { - assertEquals(data[i + lastIdx], actual[i]); + int lastIdx = counter; + for (int i = 0; i < actual.length; i ++) { + assertEquals(data[i + lastIdx], actual[i]); + } + + if (channel.parent() != null) { + channel.write(Unpooled.wrappedBuffer(actual)); + } + + counter += actual.length; } - - if (channel.parent() != null) { - channel.write(Unpooled.wrappedBuffer(actual)); - } - - counter += actual.length; + msgs.releaseAllAndRecycle(); } @Override diff --git a/testsuite/src/test/java/io/netty/testsuite/transport/socket/SocketStartTlsTest.java b/testsuite/src/test/java/io/netty/testsuite/transport/socket/SocketStartTlsTest.java index 54b70d15a9..d50fbaad20 100644 --- a/testsuite/src/test/java/io/netty/testsuite/transport/socket/SocketStartTlsTest.java +++ b/testsuite/src/test/java/io/netty/testsuite/transport/socket/SocketStartTlsTest.java @@ -19,9 +19,10 @@ import io.netty.bootstrap.Bootstrap; import io.netty.bootstrap.ServerBootstrap; import io.netty.channel.Channel; import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.ChannelInboundMessageHandlerAdapter; +import io.netty.channel.ChannelInboundHandlerAdapter; import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelPipeline; +import io.netty.channel.MessageList; import io.netty.channel.socket.SocketChannel; import io.netty.handler.codec.LineBasedFrameDecoder; import io.netty.handler.codec.string.StringDecoder; @@ -142,7 +143,7 @@ public class SocketStartTlsTest extends AbstractSocketTest { } } - private class StartTlsClientHandler extends ChannelInboundMessageHandlerAdapter { + private class StartTlsClientHandler extends ChannelInboundHandlerAdapter { private final SslHandler sslHandler; private Future handshakeFuture; final AtomicReference exception = new AtomicReference(); @@ -159,18 +160,22 @@ public class SocketStartTlsTest extends AbstractSocketTest { } @Override - public void messageReceived(final ChannelHandlerContext ctx, String msg) throws Exception { - if ("StartTlsResponse".equals(msg)) { - ctx.pipeline().addAfter("logger", "ssl", sslHandler); - handshakeFuture = sslHandler.handshakeFuture(); - ctx.write("EncryptedRequest\n"); - return; - } + public void messageReceived(ChannelHandlerContext ctx, MessageList msgs) throws Exception { + for (int i = 0; i < msgs.size(); i ++) { + String msg = (String) msgs.get(i); + if ("StartTlsResponse".equals(msg)) { + ctx.pipeline().addAfter("logger", "ssl", sslHandler); + handshakeFuture = sslHandler.handshakeFuture(); + ctx.write("EncryptedRequest\n"); + continue; + } - assertEquals("EncryptedResponse", msg); - assertNotNull(handshakeFuture); - assertTrue(handshakeFuture.isSuccess()); - ctx.close(); + assertEquals("EncryptedResponse", msg); + assertNotNull(handshakeFuture); + assertTrue(handshakeFuture.isSuccess()); + ctx.close(); + } + msgs.releaseAllAndRecycle(); } @Override @@ -185,7 +190,7 @@ public class SocketStartTlsTest extends AbstractSocketTest { } } - private class StartTlsServerHandler extends ChannelInboundMessageHandlerAdapter { + private class StartTlsServerHandler extends ChannelInboundHandlerAdapter { private final SslHandler sslHandler; volatile Channel channel; final AtomicReference exception = new AtomicReference(); @@ -201,15 +206,19 @@ public class SocketStartTlsTest extends AbstractSocketTest { } @Override - public void messageReceived(final ChannelHandlerContext ctx, String msg) throws Exception { - if ("StartTlsRequest".equals(msg)) { - ctx.pipeline().addAfter("logger", "ssl", sslHandler); - ctx.write("StartTlsResponse\n"); - return; - } + public void messageReceived(ChannelHandlerContext ctx, MessageList msgs) throws Exception { + for (int i = 0; i < msgs.size(); i ++) { + String msg = (String) msgs.get(i); + if ("StartTlsRequest".equals(msg)) { + ctx.pipeline().addAfter("logger", "ssl", sslHandler); + ctx.write("StartTlsResponse\n"); + continue; + } - assertEquals("EncryptedRequest", msg); - ctx.write("EncryptedResponse\n"); + assertEquals("EncryptedRequest", msg); + ctx.write("EncryptedResponse\n"); + } + msgs.releaseAllAndRecycle(); } @Override diff --git a/testsuite/src/test/java/io/netty/testsuite/transport/socket/SocketStringEchoTest.java b/testsuite/src/test/java/io/netty/testsuite/transport/socket/SocketStringEchoTest.java index 391f567037..9cb3b2a8f9 100644 --- a/testsuite/src/test/java/io/netty/testsuite/transport/socket/SocketStringEchoTest.java +++ b/testsuite/src/test/java/io/netty/testsuite/transport/socket/SocketStringEchoTest.java @@ -17,11 +17,11 @@ package io.netty.testsuite.transport.socket; import io.netty.bootstrap.Bootstrap; import io.netty.bootstrap.ServerBootstrap; -import io.netty.buffer.BufType; import io.netty.channel.Channel; import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.ChannelInboundMessageHandlerAdapter; +import io.netty.channel.ChannelInboundHandlerAdapter; import io.netty.channel.ChannelInitializer; +import io.netty.channel.MessageList; import io.netty.channel.socket.SocketChannel; import io.netty.handler.codec.DelimiterBasedFrameDecoder; import io.netty.handler.codec.Delimiters; @@ -136,7 +136,7 @@ public class SocketStringEchoTest extends AbstractSocketTest { } } - static class StringEchoHandler extends ChannelInboundMessageHandlerAdapter { + static class StringEchoHandler extends ChannelInboundHandlerAdapter { volatile Channel channel; final AtomicReference exception = new AtomicReference(); volatile int counter; @@ -148,16 +148,19 @@ public class SocketStringEchoTest extends AbstractSocketTest { } @Override - public void messageReceived(ChannelHandlerContext ctx, - String msg) throws Exception { - assertEquals(data[counter], msg); + public void messageReceived(ChannelHandlerContext ctx, MessageList msgs) throws Exception { + for (int i = 0; i < msgs.size(); i ++) { + String msg = (String) msgs.get(i); + assertEquals(data[counter], msg); - if (channel.parent() != null) { - String delimiter = random.nextBoolean() ? "\r\n" : "\n"; - channel.write(msg + delimiter); + if (channel.parent() != null) { + String delimiter = random.nextBoolean() ? "\r\n" : "\n"; + channel.write(msg + delimiter); + } + + counter ++; } - - counter ++; + msgs.releaseAllAndRecycle(); } @Override diff --git a/testsuite/src/test/java/io/netty/testsuite/transport/socket/WriteBeforeRegisteredTest.java b/testsuite/src/test/java/io/netty/testsuite/transport/socket/WriteBeforeRegisteredTest.java index b9a2429f22..ac553d5242 100644 --- a/testsuite/src/test/java/io/netty/testsuite/transport/socket/WriteBeforeRegisteredTest.java +++ b/testsuite/src/test/java/io/netty/testsuite/transport/socket/WriteBeforeRegisteredTest.java @@ -18,7 +18,7 @@ package io.netty.testsuite.transport.socket; import io.netty.bootstrap.Bootstrap; import io.netty.buffer.Unpooled; import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.ChannelStateHandlerAdapter; +import io.netty.channel.ChannelInboundHandlerAdapter; import io.netty.channel.socket.SocketChannel; import org.junit.Test; @@ -42,12 +42,7 @@ public class WriteBeforeRegisteredTest extends AbstractClientSocketTest { } } - private static class TestHandler extends ChannelStateHandlerAdapter { - - @Override - public void inboundBufferUpdated(ChannelHandlerContext ctx) throws Exception { - ctx.fireInboundBufferUpdated(); - } + private static class TestHandler extends ChannelInboundHandlerAdapter { @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { diff --git a/testsuite/src/test/java/io/netty/testsuite/transport/udt/UDTClientServerConnectionTest.java b/testsuite/src/test/java/io/netty/testsuite/transport/udt/UDTClientServerConnectionTest.java index 314f0f2b78..dcfcc59424 100644 --- a/testsuite/src/test/java/io/netty/testsuite/transport/udt/UDTClientServerConnectionTest.java +++ b/testsuite/src/test/java/io/netty/testsuite/transport/udt/UDTClientServerConnectionTest.java @@ -15,14 +15,14 @@ */ package io.netty.testsuite.transport.udt; -import static org.junit.Assert.*; import io.netty.bootstrap.Bootstrap; import io.netty.bootstrap.ServerBootstrap; import io.netty.channel.Channel; import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.ChannelInboundMessageHandlerAdapter; +import io.netty.channel.ChannelInboundHandlerAdapter; import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelPipeline; +import io.netty.channel.MessageList; import io.netty.channel.group.ChannelGroup; import io.netty.channel.group.DefaultChannelGroup; import io.netty.channel.nio.NioEventLoopGroup; @@ -33,13 +33,14 @@ import io.netty.handler.codec.Delimiters; import io.netty.handler.codec.string.StringDecoder; import io.netty.handler.codec.string.StringEncoder; import io.netty.util.CharsetUtil; - -import java.util.concurrent.atomic.AtomicInteger; - import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.util.concurrent.atomic.AtomicInteger; + +import static org.junit.Assert.*; + /** * Verify UDT connect/disconnect life cycle. */ @@ -136,7 +137,7 @@ public class UDTClientServerConnectionTest { } static class ClientHandler extends - ChannelInboundMessageHandlerAdapter { + ChannelInboundHandlerAdapter { static final Logger log = LoggerFactory.getLogger(ClientHandler.class); @@ -169,9 +170,11 @@ public class UDTClientServerConnectionTest { } @Override - public void messageReceived(final ChannelHandlerContext ctx, - final String msg) throws Exception { - log.info("Client received: " + msg); + public void messageReceived(ChannelHandlerContext ctx, MessageList msgs) throws Exception { + for (int i = 0; i < msgs.size(); i ++) { + log.info("Client received: " + msgs.get(i)); + } + msgs.releaseAllAndRecycle(); } } @@ -282,7 +285,7 @@ public class UDTClientServerConnectionTest { } static class ServerHandler extends - ChannelInboundMessageHandlerAdapter { + ChannelInboundHandlerAdapter { static final Logger log = LoggerFactory.getLogger(ServerHandler.class); @@ -320,9 +323,11 @@ public class UDTClientServerConnectionTest { } @Override - public void messageReceived(final ChannelHandlerContext ctx, - final String message) throws Exception { - log.info("Server received: " + message); + public void messageReceived(ChannelHandlerContext ctx, MessageList msgs) throws Exception { + for (int i = 0; i < msgs.size(); i ++) { + log.info("Server received: " + msgs.get(i)); + } + msgs.releaseAllAndRecycle(); } } diff --git a/transport-rxtx/pom.xml b/transport-rxtx/pom.xml index 249b43579d..8976db43ab 100644 --- a/transport-rxtx/pom.xml +++ b/transport-rxtx/pom.xml @@ -21,7 +21,7 @@ io.netty netty-parent - 4.0.0.Final-SNAPSHOT + 4.0.0.CR4-SNAPSHOT netty-transport-rxtx @@ -35,11 +35,6 @@ netty-buffer ${project.version} - - ${project.groupId} - netty-codec - ${project.version} - ${project.groupId} netty-transport diff --git a/transport-rxtx/src/main/java/io/netty/channel/rxtx/DefaultRxtxChannelConfig.java b/transport-rxtx/src/main/java/io/netty/channel/rxtx/DefaultRxtxChannelConfig.java index 6a9d7df032..63d4f3e852 100644 --- a/transport-rxtx/src/main/java/io/netty/channel/rxtx/DefaultRxtxChannelConfig.java +++ b/transport-rxtx/src/main/java/io/netty/channel/rxtx/DefaultRxtxChannelConfig.java @@ -18,6 +18,7 @@ package io.netty.channel.rxtx; import io.netty.buffer.ByteBufAllocator; import io.netty.channel.ChannelOption; import io.netty.channel.DefaultChannelConfig; +import io.netty.channel.RecvByteBufAllocator; import java.util.Map; @@ -191,13 +192,24 @@ final class DefaultRxtxChannelConfig extends DefaultChannelConfig implements Rxt return (RxtxChannelConfig) super.setAllocator(allocator); } + @Override + public RxtxChannelConfig setRecvByteBufAllocator(RecvByteBufAllocator allocator) { + super.setRecvByteBufAllocator(allocator); + return this; + } + @Override public RxtxChannelConfig setAutoRead(boolean autoRead) { return (RxtxChannelConfig) super.setAutoRead(autoRead); } @Override - public RxtxChannelConfig setDefaultHandlerByteBufType(ChannelHandlerByteBufType type) { - return (RxtxChannelConfig) super.setDefaultHandlerByteBufType(type); + public RxtxChannelConfig setWriteBufferHighWaterMark(int writeBufferHighWaterMark) { + return (RxtxChannelConfig) super.setWriteBufferHighWaterMark(writeBufferHighWaterMark); + } + + @Override + public RxtxChannelConfig setWriteBufferLowWaterMark(int writeBufferLowWaterMark) { + return (RxtxChannelConfig) super.setWriteBufferLowWaterMark(writeBufferLowWaterMark); } } diff --git a/transport-rxtx/src/main/java/io/netty/channel/rxtx/RxtxChannelConfig.java b/transport-rxtx/src/main/java/io/netty/channel/rxtx/RxtxChannelConfig.java index 382601bbf6..6085b851c3 100644 --- a/transport-rxtx/src/main/java/io/netty/channel/rxtx/RxtxChannelConfig.java +++ b/transport-rxtx/src/main/java/io/netty/channel/rxtx/RxtxChannelConfig.java @@ -18,6 +18,7 @@ package io.netty.channel.rxtx; import gnu.io.SerialPort; import io.netty.buffer.ByteBufAllocator; import io.netty.channel.ChannelConfig; +import io.netty.channel.RecvByteBufAllocator; /** * A configuration class for RXTX device connections. @@ -268,8 +269,8 @@ public interface RxtxChannelConfig extends ChannelConfig { RxtxChannelConfig setAllocator(ByteBufAllocator allocator); @Override - RxtxChannelConfig setAutoRead(boolean autoRead); + RxtxChannelConfig setRecvByteBufAllocator(RecvByteBufAllocator allocator); @Override - RxtxChannelConfig setDefaultHandlerByteBufType(ChannelHandlerByteBufType type); + RxtxChannelConfig setAutoRead(boolean autoRead); } diff --git a/transport-sctp/pom.xml b/transport-sctp/pom.xml index b6216bc99b..a6175f8612 100644 --- a/transport-sctp/pom.xml +++ b/transport-sctp/pom.xml @@ -20,7 +20,7 @@ io.netty netty-parent - 4.0.0.Final-SNAPSHOT + 4.0.0.CR4-SNAPSHOT netty-transport-sctp diff --git a/transport-sctp/src/main/java/io/netty/channel/sctp/DefaultSctpChannelConfig.java b/transport-sctp/src/main/java/io/netty/channel/sctp/DefaultSctpChannelConfig.java index 687d9a3828..baeb008f5f 100644 --- a/transport-sctp/src/main/java/io/netty/channel/sctp/DefaultSctpChannelConfig.java +++ b/transport-sctp/src/main/java/io/netty/channel/sctp/DefaultSctpChannelConfig.java @@ -19,10 +19,10 @@ package io.netty.channel.sctp; import com.sun.nio.sctp.SctpChannel; import com.sun.nio.sctp.SctpStandardSocketOptions; import io.netty.buffer.ByteBufAllocator; -import io.netty.channel.ChannelConfig; import io.netty.channel.ChannelException; import io.netty.channel.ChannelOption; import io.netty.channel.DefaultChannelConfig; +import io.netty.channel.RecvByteBufAllocator; import io.netty.util.internal.PlatformDependent; import java.io.IOException; @@ -186,13 +186,24 @@ public class DefaultSctpChannelConfig extends DefaultChannelConfig implements Sc return (SctpChannelConfig) super.setAllocator(allocator); } + @Override + public SctpChannelConfig setRecvByteBufAllocator(RecvByteBufAllocator allocator) { + super.setRecvByteBufAllocator(allocator); + return this; + } + @Override public SctpChannelConfig setAutoRead(boolean autoRead) { return (SctpChannelConfig) super.setAutoRead(autoRead); } @Override - public SctpChannelConfig setDefaultHandlerByteBufType(ChannelHandlerByteBufType type) { - return (SctpChannelConfig) super.setDefaultHandlerByteBufType(type); + public SctpChannelConfig setWriteBufferHighWaterMark(int writeBufferHighWaterMark) { + return (SctpChannelConfig) super.setWriteBufferHighWaterMark(writeBufferHighWaterMark); + } + + @Override + public SctpChannelConfig setWriteBufferLowWaterMark(int writeBufferLowWaterMark) { + return (SctpChannelConfig) super.setWriteBufferLowWaterMark(writeBufferLowWaterMark); } } diff --git a/transport-sctp/src/main/java/io/netty/channel/sctp/DefaultSctpServerChannelConfig.java b/transport-sctp/src/main/java/io/netty/channel/sctp/DefaultSctpServerChannelConfig.java index f1e820bb02..055e6e8421 100644 --- a/transport-sctp/src/main/java/io/netty/channel/sctp/DefaultSctpServerChannelConfig.java +++ b/transport-sctp/src/main/java/io/netty/channel/sctp/DefaultSctpServerChannelConfig.java @@ -20,6 +20,7 @@ import io.netty.buffer.ByteBufAllocator; import io.netty.channel.ChannelException; import io.netty.channel.ChannelOption; import io.netty.channel.DefaultChannelConfig; +import io.netty.channel.RecvByteBufAllocator; import io.netty.util.NetUtil; import java.io.IOException; @@ -169,13 +170,24 @@ public class DefaultSctpServerChannelConfig extends DefaultChannelConfig impleme return (SctpServerChannelConfig) super.setAllocator(allocator); } + @Override + public SctpServerChannelConfig setRecvByteBufAllocator(RecvByteBufAllocator allocator) { + super.setRecvByteBufAllocator(allocator); + return this; + } + @Override public SctpServerChannelConfig setAutoRead(boolean autoRead) { return (SctpServerChannelConfig) super.setAutoRead(autoRead); } @Override - public SctpServerChannelConfig setDefaultHandlerByteBufType(ChannelHandlerByteBufType type) { - return (SctpServerChannelConfig) super.setDefaultHandlerByteBufType(type); + public SctpServerChannelConfig setWriteBufferLowWaterMark(int writeBufferLowWaterMark) { + return (SctpServerChannelConfig) super.setWriteBufferLowWaterMark(writeBufferLowWaterMark); + } + + @Override + public SctpServerChannelConfig setWriteBufferHighWaterMark(int writeBufferHighWaterMark) { + return (SctpServerChannelConfig) super.setWriteBufferHighWaterMark(writeBufferHighWaterMark); } } diff --git a/transport-sctp/src/main/java/io/netty/channel/sctp/SctpChannelConfig.java b/transport-sctp/src/main/java/io/netty/channel/sctp/SctpChannelConfig.java index 341a756f78..7cb3da86f8 100644 --- a/transport-sctp/src/main/java/io/netty/channel/sctp/SctpChannelConfig.java +++ b/transport-sctp/src/main/java/io/netty/channel/sctp/SctpChannelConfig.java @@ -15,10 +15,10 @@ */ package io.netty.channel.sctp; +import com.sun.nio.sctp.SctpStandardSocketOptions.InitMaxStreams; import io.netty.buffer.ByteBufAllocator; import io.netty.channel.ChannelConfig; - -import static com.sun.nio.sctp.SctpStandardSocketOptions.*; +import io.netty.channel.RecvByteBufAllocator; /** * A {@link ChannelConfig} for a {@link SctpChannel}. @@ -106,8 +106,8 @@ public interface SctpChannelConfig extends ChannelConfig { SctpChannelConfig setAllocator(ByteBufAllocator allocator); @Override - SctpChannelConfig setAutoRead(boolean autoRead); + SctpChannelConfig setRecvByteBufAllocator(RecvByteBufAllocator allocator); @Override - SctpChannelConfig setDefaultHandlerByteBufType(ChannelHandlerByteBufType type); + SctpChannelConfig setAutoRead(boolean autoRead); } diff --git a/transport-sctp/src/main/java/io/netty/channel/sctp/SctpMessage.java b/transport-sctp/src/main/java/io/netty/channel/sctp/SctpMessage.java index b3cebf8a90..84b2c03504 100644 --- a/transport-sctp/src/main/java/io/netty/channel/sctp/SctpMessage.java +++ b/transport-sctp/src/main/java/io/netty/channel/sctp/SctpMessage.java @@ -16,8 +16,8 @@ package io.netty.channel.sctp; import com.sun.nio.sctp.MessageInfo; -import io.netty.buffer.BufUtil; import io.netty.buffer.ByteBuf; +import io.netty.buffer.ByteBufUtil; import io.netty.buffer.DefaultByteBufHolder; /** @@ -156,6 +156,6 @@ public final class SctpMessage extends DefaultByteBufHolder { } return "SctpFrame{" + "streamIdentifier=" + streamIdentifier + ", protocolIdentifier=" + protocolIdentifier + - ", data=" + BufUtil.hexDump(content()) + '}'; + ", data=" + ByteBufUtil.hexDump(content()) + '}'; } } diff --git a/transport-sctp/src/main/java/io/netty/channel/sctp/SctpServerChannelConfig.java b/transport-sctp/src/main/java/io/netty/channel/sctp/SctpServerChannelConfig.java index 26844dad7f..7527b46894 100644 --- a/transport-sctp/src/main/java/io/netty/channel/sctp/SctpServerChannelConfig.java +++ b/transport-sctp/src/main/java/io/netty/channel/sctp/SctpServerChannelConfig.java @@ -15,10 +15,10 @@ */ package io.netty.channel.sctp; +import com.sun.nio.sctp.SctpStandardSocketOptions.InitMaxStreams; import io.netty.buffer.ByteBufAllocator; import io.netty.channel.ChannelConfig; - -import static com.sun.nio.sctp.SctpStandardSocketOptions.*; +import io.netty.channel.RecvByteBufAllocator; /** * A {@link ChannelConfig} for a {@link SctpServerChannelConfig}. @@ -101,8 +101,8 @@ public interface SctpServerChannelConfig extends ChannelConfig { SctpServerChannelConfig setAllocator(ByteBufAllocator allocator); @Override - SctpServerChannelConfig setAutoRead(boolean autoRead); + SctpServerChannelConfig setRecvByteBufAllocator(RecvByteBufAllocator allocator); @Override - SctpServerChannelConfig setDefaultHandlerByteBufType(ChannelHandlerByteBufType type); + SctpServerChannelConfig setAutoRead(boolean autoRead); } diff --git a/transport-sctp/src/main/java/io/netty/channel/sctp/nio/NioSctpChannel.java b/transport-sctp/src/main/java/io/netty/channel/sctp/nio/NioSctpChannel.java index 92f9555fd1..a2a42d31ff 100644 --- a/transport-sctp/src/main/java/io/netty/channel/sctp/nio/NioSctpChannel.java +++ b/transport-sctp/src/main/java/io/netty/channel/sctp/nio/NioSctpChannel.java @@ -19,14 +19,13 @@ import com.sun.nio.sctp.Association; import com.sun.nio.sctp.MessageInfo; import com.sun.nio.sctp.NotificationHandler; import com.sun.nio.sctp.SctpChannel; -import io.netty.buffer.BufType; import io.netty.buffer.ByteBuf; -import io.netty.buffer.MessageBuf; import io.netty.channel.Channel; import io.netty.channel.ChannelException; import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelMetadata; import io.netty.channel.ChannelPromise; +import io.netty.channel.MessageList; import io.netty.channel.nio.AbstractNioMessageChannel; import io.netty.channel.sctp.DefaultSctpChannelConfig; import io.netty.channel.sctp.SctpChannelConfig; @@ -57,14 +56,13 @@ import java.util.Set; * to understand what you need to do to use it. Also this feature is only supported on Java 7+. */ public class NioSctpChannel extends AbstractNioMessageChannel implements io.netty.channel.sctp.SctpChannel { - private static final ChannelMetadata METADATA = new ChannelMetadata(BufType.MESSAGE, false); + private static final ChannelMetadata METADATA = new ChannelMetadata(false); private static final InternalLogger logger = InternalLoggerFactory.getInstance(NioSctpChannel.class); private final SctpChannelConfig config; - @SuppressWarnings("rawtypes") - private final NotificationHandler notificationHandler; + private final NotificationHandler notificationHandler; private static SctpChannel newSctpChannel() { try { @@ -259,9 +257,8 @@ public class NioSctpChannel extends AbstractNioMessageChannel implements io.nett javaChannel().close(); } - @SuppressWarnings("unchecked") @Override - protected int doReadMessages(MessageBuf buf) throws Exception { + protected int doReadMessages(MessageList buf) throws Exception { SctpChannel ch = javaChannel(); ByteBuf buffer = alloc().directBuffer(config().getReceiveBufferSize()); boolean free = true; @@ -287,8 +284,8 @@ public class NioSctpChannel extends AbstractNioMessageChannel implements io.nett } @Override - protected int doWriteMessages(MessageBuf buf, boolean lastSpin) throws Exception { - SctpMessage packet = (SctpMessage) buf.peek(); + protected int doWriteMessages(MessageList msgs, int index, boolean lastSpin) throws Exception { + SctpMessage packet = (SctpMessage) msgs.get(index); ByteBuf data = packet.content(); int dataLen = data.readableBytes(); ByteBuffer nioData; @@ -322,13 +319,10 @@ public class NioSctpChannel extends AbstractNioMessageChannel implements io.nett return 0; } - // Wrote a packet. - buf.remove(); - // packet was written free up buffer packet.release(); - if (buf.isEmpty()) { + if (index + 1 == msgs.size()) { // Wrote the outbound buffer completely - clear OP_WRITE. if ((interestOps & SelectionKey.OP_WRITE) != 0) { key.interestOps(interestOps & ~SelectionKey.OP_WRITE); diff --git a/transport-sctp/src/main/java/io/netty/channel/sctp/nio/NioSctpServerChannel.java b/transport-sctp/src/main/java/io/netty/channel/sctp/nio/NioSctpServerChannel.java index a645b77a0c..c2e52bdc90 100644 --- a/transport-sctp/src/main/java/io/netty/channel/sctp/nio/NioSctpServerChannel.java +++ b/transport-sctp/src/main/java/io/netty/channel/sctp/nio/NioSctpServerChannel.java @@ -17,12 +17,11 @@ package io.netty.channel.sctp.nio; import com.sun.nio.sctp.SctpChannel; import com.sun.nio.sctp.SctpServerChannel; -import io.netty.buffer.BufType; -import io.netty.buffer.MessageBuf; import io.netty.channel.ChannelException; import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelMetadata; import io.netty.channel.ChannelPromise; +import io.netty.channel.MessageList; import io.netty.channel.nio.AbstractNioMessageChannel; import io.netty.channel.sctp.DefaultSctpServerChannelConfig; import io.netty.channel.sctp.SctpServerChannelConfig; @@ -46,7 +45,7 @@ import java.util.Set; */ public class NioSctpServerChannel extends AbstractNioMessageChannel implements io.netty.channel.sctp.SctpServerChannel { - private static final ChannelMetadata METADATA = new ChannelMetadata(BufType.MESSAGE, false); + private static final ChannelMetadata METADATA = new ChannelMetadata(false); private static SctpServerChannel newSocket() { try { @@ -135,7 +134,7 @@ public class NioSctpServerChannel extends AbstractNioMessageChannel } @Override - protected int doReadMessages(MessageBuf buf) throws Exception { + protected int doReadMessages(MessageList buf) throws Exception { SctpChannel ch = javaChannel().accept(); if (ch == null) { return 0; @@ -217,7 +216,7 @@ public class NioSctpServerChannel extends AbstractNioMessageChannel } @Override - protected int doWriteMessages(MessageBuf buf, boolean lastSpin) throws Exception { + protected int doWriteMessages(MessageList msgs, int index, boolean lastSpin) throws Exception { throw new UnsupportedOperationException(); } } diff --git a/transport-sctp/src/main/java/io/netty/channel/sctp/oio/OioSctpChannel.java b/transport-sctp/src/main/java/io/netty/channel/sctp/oio/OioSctpChannel.java index 72792f7a02..b818673285 100755 --- a/transport-sctp/src/main/java/io/netty/channel/sctp/oio/OioSctpChannel.java +++ b/transport-sctp/src/main/java/io/netty/channel/sctp/oio/OioSctpChannel.java @@ -19,14 +19,13 @@ import com.sun.nio.sctp.Association; import com.sun.nio.sctp.MessageInfo; import com.sun.nio.sctp.NotificationHandler; import com.sun.nio.sctp.SctpChannel; -import io.netty.buffer.BufType; import io.netty.buffer.ByteBuf; -import io.netty.buffer.MessageBuf; import io.netty.channel.Channel; import io.netty.channel.ChannelException; import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelMetadata; import io.netty.channel.ChannelPromise; +import io.netty.channel.MessageList; import io.netty.channel.oio.AbstractOioMessageChannel; import io.netty.channel.sctp.DefaultSctpChannelConfig; import io.netty.channel.sctp.SctpChannelConfig; @@ -62,7 +61,7 @@ public class OioSctpChannel extends AbstractOioMessageChannel private static final InternalLogger logger = InternalLoggerFactory.getInstance(OioSctpChannel.class); - private static final ChannelMetadata METADATA = new ChannelMetadata(BufType.MESSAGE, false); + private static final ChannelMetadata METADATA = new ChannelMetadata(false); private final SctpChannel ch; private final SctpChannelConfig config; @@ -166,7 +165,7 @@ public class OioSctpChannel extends AbstractOioMessageChannel } @Override - protected int doReadMessages(MessageBuf buf) throws Exception { + protected int doReadMessages(MessageList buf) throws Exception { if (!readSelector.isOpen()) { return 0; } @@ -213,17 +212,31 @@ public class OioSctpChannel extends AbstractOioMessageChannel } @Override - protected void doWriteMessages(MessageBuf buf) throws Exception { + protected int doWrite(MessageList msgs, int index) throws Exception { if (!writeSelector.isOpen()) { - return; + return 0; } final int selectedKeys = writeSelector.select(SO_TIMEOUT); if (selectedKeys > 0) { final Set writableKeys = writeSelector.selectedKeys(); - for (SelectionKey ignored : writableKeys) { - SctpMessage packet = (SctpMessage) buf.poll(); + if (writableKeys.isEmpty()) { + return 0; + } + Iterator writableKeysIt = writableKeys.iterator(); + int written = 0; + int length = msgs.size() - index; + + for (;;) { + if (written == length) { + // all written + return written; + } + writableKeysIt.next(); + writableKeysIt.remove(); + + SctpMessage packet = (SctpMessage) msgs.get(index ++); if (packet == null) { - return; + return written; } try { ByteBuf data = packet.content(); @@ -243,12 +256,17 @@ public class OioSctpChannel extends AbstractOioMessageChannel mi.streamNumber(packet.streamIdentifier()); ch.send(nioData, mi); + written ++; } finally { packet.release(); } + if (!writableKeysIt.hasNext()) { + return written; + } } - writableKeys.clear(); } + + return 0; } @Override diff --git a/transport-sctp/src/main/java/io/netty/channel/sctp/oio/OioSctpServerChannel.java b/transport-sctp/src/main/java/io/netty/channel/sctp/oio/OioSctpServerChannel.java index 4f12c3ac22..85b0d5b514 100755 --- a/transport-sctp/src/main/java/io/netty/channel/sctp/oio/OioSctpServerChannel.java +++ b/transport-sctp/src/main/java/io/netty/channel/sctp/oio/OioSctpServerChannel.java @@ -17,12 +17,12 @@ package io.netty.channel.sctp.oio; import com.sun.nio.sctp.SctpChannel; import com.sun.nio.sctp.SctpServerChannel; -import io.netty.buffer.BufType; -import io.netty.buffer.MessageBuf; +import io.netty.buffer.ByteBufUtil; import io.netty.channel.ChannelException; import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelMetadata; import io.netty.channel.ChannelPromise; +import io.netty.channel.MessageList; import io.netty.channel.oio.AbstractOioMessageChannel; import io.netty.channel.sctp.DefaultSctpServerChannelConfig; import io.netty.channel.sctp.SctpServerChannelConfig; @@ -53,7 +53,7 @@ public class OioSctpServerChannel extends AbstractOioMessageChannel private static final InternalLogger logger = InternalLoggerFactory.getInstance(OioSctpServerChannel.class); - private static final ChannelMetadata METADATA = new ChannelMetadata(BufType.MESSAGE, false); + private static final ChannelMetadata METADATA = new ChannelMetadata(false); private static SctpServerChannel newServerSocket() { try { @@ -189,27 +189,32 @@ public class OioSctpServerChannel extends AbstractOioMessageChannel } @Override - protected int doReadMessages(MessageBuf buf) throws Exception { + protected int doReadMessages(MessageList buf) throws Exception { if (!isActive()) { return -1; } SctpChannel s = null; + int acceptedChannels = 0; try { final int selectedKeys = selector.select(SO_TIMEOUT); if (selectedKeys > 0) { - final Set selectionKeys = selector.selectedKeys(); - for (SelectionKey key : selectionKeys) { - if (key.isAcceptable()) { - s = sch.accept(); - if (s != null) { - buf.add(new OioSctpChannel(this, null, s)); - } - } + final Iterator selectionKeys = selector.selectedKeys().iterator(); + for (;;) { + SelectionKey key = selectionKeys.next(); + selectionKeys.remove(); + if (key.isAcceptable()) { + s = sch.accept(); + if (s != null) { + buf.add(new OioSctpChannel(this, null, s)); + acceptedChannels ++; + } + } + if (!selectionKeys.hasNext()) { + return acceptedChannels; + } } - return selectedKeys; } - } catch (Throwable t) { logger.warn("Failed to create a new channel from an accepted sctp channel.", t); if (s != null) { @@ -221,7 +226,7 @@ public class OioSctpServerChannel extends AbstractOioMessageChannel } } - return 0; + return acceptedChannels; } @Override @@ -291,7 +296,11 @@ public class OioSctpServerChannel extends AbstractOioMessageChannel } @Override - protected void doWriteMessages(MessageBuf buf) throws Exception { + protected int doWrite(MessageList msgs, int index) throws Exception { + int size = msgs.size(); + for (int i = index; i < size; i ++) { + ByteBufUtil.release(msgs.get(i)); + } throw new UnsupportedOperationException(); } } diff --git a/transport-sctp/src/main/java/io/netty/handler/codec/sctp/SctpInboundByteStreamHandler.java b/transport-sctp/src/main/java/io/netty/handler/codec/sctp/SctpInboundByteStreamHandler.java index 209aad0d78..fb1e2bb596 100644 --- a/transport-sctp/src/main/java/io/netty/handler/codec/sctp/SctpInboundByteStreamHandler.java +++ b/transport-sctp/src/main/java/io/netty/handler/codec/sctp/SctpInboundByteStreamHandler.java @@ -18,15 +18,16 @@ package io.netty.handler.codec.sctp; import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.ChannelInboundMessageHandlerAdapter; +import io.netty.channel.MessageList; import io.netty.channel.sctp.SctpMessage; import io.netty.handler.codec.CodecException; +import io.netty.handler.codec.MessageToMessageDecoder; /** * A ChannelHandler which receives {@link SctpMessage}s which belong to a application protocol form a specific * SCTP Stream and decode it as {@link ByteBuf}. */ -public class SctpInboundByteStreamHandler extends ChannelInboundMessageHandlerAdapter { +public class SctpInboundByteStreamHandler extends MessageToMessageDecoder { private final int protocolIdentifier; private final int streamIdentifier; @@ -52,13 +53,11 @@ public class SctpInboundByteStreamHandler extends ChannelInboundMessageHandlerAd } @Override - public void messageReceived(ChannelHandlerContext ctx, SctpMessage msg) throws Exception { + protected void decode(ChannelHandlerContext ctx, SctpMessage msg, MessageList out) throws Exception { if (!msg.isComplete()) { throw new CodecException(String.format("Received SctpMessage is not complete, please add %s in the " + "pipeline before this handler", SctpMessageCompletionHandler.class.getSimpleName())); } - - ctx.nextInboundByteBuffer().writeBytes(msg.content()); - ctx.fireInboundBufferUpdated(); + out.add(msg.content().retain()); } } diff --git a/transport-sctp/src/main/java/io/netty/handler/codec/sctp/SctpMessageCompletionHandler.java b/transport-sctp/src/main/java/io/netty/handler/codec/sctp/SctpMessageCompletionHandler.java index e84e31f260..355d36e076 100644 --- a/transport-sctp/src/main/java/io/netty/handler/codec/sctp/SctpMessageCompletionHandler.java +++ b/transport-sctp/src/main/java/io/netty/handler/codec/sctp/SctpMessageCompletionHandler.java @@ -19,47 +19,30 @@ package io.netty.handler.codec.sctp; import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.ChannelInboundMessageHandler; -import io.netty.channel.ChannelInboundMessageHandlerAdapter; +import io.netty.channel.ChannelInboundHandler; +import io.netty.channel.MessageList; import io.netty.channel.sctp.SctpMessage; +import io.netty.handler.codec.MessageToMessageDecoder; import java.util.HashMap; import java.util.Map; /** - * {@link ChannelInboundMessageHandlerAdapter} which will take care of handle fragmented {@link SctpMessage}s, so + * {@link MessageToMessageDecoder} which will take care of handle fragmented {@link SctpMessage}s, so * only complete {@link SctpMessage}s will be forwarded to the next - * {@link ChannelInboundMessageHandler}. + * {@link ChannelInboundHandler}. */ -public class SctpMessageCompletionHandler extends ChannelInboundMessageHandlerAdapter { +public class SctpMessageCompletionHandler extends MessageToMessageDecoder { private final Map fragments = new HashMap(); - private boolean assembled; @Override - public boolean beginMessageReceived(ChannelHandlerContext ctx) throws Exception { - assembled = false; - return super.beginMessageReceived(ctx); - } - - @Override - public void endMessageReceived(ChannelHandlerContext ctx) throws Exception { - if (assembled) { - assembled = false; - ctx.fireInboundBufferUpdated(); - } - super.endMessageReceived(ctx); - } - - @Override - public void messageReceived(ChannelHandlerContext ctx, SctpMessage msg) throws Exception { - + protected void decode(ChannelHandlerContext ctx, SctpMessage msg, MessageList out) throws Exception { final ByteBuf byteBuf = msg.content(); final int protocolIdentifier = msg.protocolIdentifier(); final int streamIdentifier = msg.streamIdentifier(); final boolean isComplete = msg.isComplete(); ByteBuf frag; - if (fragments.containsKey(streamIdentifier)) { frag = fragments.remove(streamIdentifier); } else { @@ -68,7 +51,7 @@ public class SctpMessageCompletionHandler extends ChannelInboundMessageHandlerAd if (isComplete && !frag.isReadable()) { //data chunk is not fragmented - handleAssembledMessage(ctx, msg); + out.add(msg); } else if (!isComplete && frag.isReadable()) { //more message to complete fragments.put(streamIdentifier, Unpooled.wrappedBuffer(frag, byteBuf)); @@ -79,17 +62,11 @@ public class SctpMessageCompletionHandler extends ChannelInboundMessageHandlerAd protocolIdentifier, streamIdentifier, Unpooled.wrappedBuffer(frag, byteBuf)); - handleAssembledMessage(ctx, assembledMsg); + out.add(assembledMsg); } else { //first incomplete message fragments.put(streamIdentifier, byteBuf); } - byteBuf.retain(); } - - private void handleAssembledMessage(ChannelHandlerContext ctx, SctpMessage assembledMsg) { - ctx.nextInboundMessageBuffer().add(assembledMsg); - assembled = true; - } } diff --git a/transport-sctp/src/main/java/io/netty/handler/codec/sctp/SctpOutboundByteStreamHandler.java b/transport-sctp/src/main/java/io/netty/handler/codec/sctp/SctpOutboundByteStreamHandler.java index f4ff1cfc79..09e7bbf803 100644 --- a/transport-sctp/src/main/java/io/netty/handler/codec/sctp/SctpOutboundByteStreamHandler.java +++ b/transport-sctp/src/main/java/io/netty/handler/codec/sctp/SctpOutboundByteStreamHandler.java @@ -16,20 +16,17 @@ package io.netty.handler.codec.sctp; import io.netty.buffer.ByteBuf; -import io.netty.buffer.MessageBuf; -import io.netty.buffer.Unpooled; import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.ChannelOutboundByteHandlerAdapter; -import io.netty.channel.ChannelPromise; +import io.netty.channel.MessageList; import io.netty.channel.sctp.SctpMessage; -import io.netty.handler.codec.EncoderException; +import io.netty.handler.codec.MessageToMessageEncoder; /** * A ChannelHandler which transform {@link ByteBuf} to {@link SctpMessage} and send it through a specific stream * with given protocol identifier. * */ -public class SctpOutboundByteStreamHandler extends ChannelOutboundByteHandlerAdapter { +public class SctpOutboundByteStreamHandler extends MessageToMessageEncoder { private final int streamIdentifier; private final int protocolIdentifier; @@ -43,16 +40,7 @@ public class SctpOutboundByteStreamHandler extends ChannelOutboundByteHandlerAda } @Override - protected void flush(ChannelHandlerContext ctx, ByteBuf in, ChannelPromise promise) throws Exception { - try { - MessageBuf out = ctx.nextOutboundMessageBuffer(); - ByteBuf payload = Unpooled.buffer(in.readableBytes()); - payload.writeBytes(in); - out.add(new SctpMessage(streamIdentifier, protocolIdentifier, payload)); - } catch (Throwable t) { - ctx.fireExceptionCaught(new EncoderException(t)); - } - - ctx.flush(promise); + protected void encode(ChannelHandlerContext ctx, ByteBuf msg, MessageList out) throws Exception { + out.add(new SctpMessage(streamIdentifier, protocolIdentifier, msg.retain())); } } diff --git a/transport-udt/pom.xml b/transport-udt/pom.xml index 698064801f..9fedc1701c 100644 --- a/transport-udt/pom.xml +++ b/transport-udt/pom.xml @@ -21,7 +21,7 @@ io.netty netty-parent - 4.0.0.Final-SNAPSHOT + 4.0.0.CR4-SNAPSHOT netty-transport-udt diff --git a/transport-udt/src/main/java/io/netty/channel/udt/DefaultUdtChannelConfig.java b/transport-udt/src/main/java/io/netty/channel/udt/DefaultUdtChannelConfig.java index fb5ca654cf..5495f9792b 100644 --- a/transport-udt/src/main/java/io/netty/channel/udt/DefaultUdtChannelConfig.java +++ b/transport-udt/src/main/java/io/netty/channel/udt/DefaultUdtChannelConfig.java @@ -19,9 +19,9 @@ import com.barchart.udt.OptionUDT; import com.barchart.udt.SocketUDT; import com.barchart.udt.nio.ChannelUDT; import io.netty.buffer.ByteBufAllocator; -import io.netty.channel.ChannelConfig; import io.netty.channel.ChannelOption; import io.netty.channel.DefaultChannelConfig; +import io.netty.channel.RecvByteBufAllocator; import java.io.IOException; import java.util.Map; @@ -250,6 +250,12 @@ public class DefaultUdtChannelConfig extends DefaultChannelConfig implements return this; } + @Override + public UdtChannelConfig setRecvByteBufAllocator(RecvByteBufAllocator allocator) { + super.setRecvByteBufAllocator(allocator); + return this; + } + @Override public UdtChannelConfig setAutoRead(boolean autoRead) { super.setAutoRead(autoRead); @@ -257,8 +263,12 @@ public class DefaultUdtChannelConfig extends DefaultChannelConfig implements } @Override - public UdtChannelConfig setDefaultHandlerByteBufType(ChannelHandlerByteBufType type) { - super.setDefaultHandlerByteBufType(type); - return this; + public UdtChannelConfig setWriteBufferLowWaterMark(int writeBufferLowWaterMark) { + return (UdtChannelConfig) super.setWriteBufferLowWaterMark(writeBufferLowWaterMark); + } + + @Override + public UdtChannelConfig setWriteBufferHighWaterMark(int writeBufferHighWaterMark) { + return (UdtChannelConfig) super.setWriteBufferHighWaterMark(writeBufferHighWaterMark); } } diff --git a/transport-udt/src/main/java/io/netty/channel/udt/DefaultUdtServerChannelConfig.java b/transport-udt/src/main/java/io/netty/channel/udt/DefaultUdtServerChannelConfig.java index 315eb92033..8437db011f 100644 --- a/transport-udt/src/main/java/io/netty/channel/udt/DefaultUdtServerChannelConfig.java +++ b/transport-udt/src/main/java/io/netty/channel/udt/DefaultUdtServerChannelConfig.java @@ -18,6 +18,7 @@ package io.netty.channel.udt; import com.barchart.udt.nio.ChannelUDT; import io.netty.buffer.ByteBufAllocator; import io.netty.channel.ChannelOption; +import io.netty.channel.RecvByteBufAllocator; import java.io.IOException; import java.util.Map; @@ -153,14 +154,14 @@ public class DefaultUdtServerChannelConfig extends DefaultUdtChannelConfig } @Override - public UdtServerChannelConfig setAutoRead(boolean autoRead) { - super.setAutoRead(autoRead); + public UdtServerChannelConfig setRecvByteBufAllocator(RecvByteBufAllocator allocator) { + super.setRecvByteBufAllocator(allocator); return this; } @Override - public UdtServerChannelConfig setDefaultHandlerByteBufType(ChannelHandlerByteBufType type) { - super.setDefaultHandlerByteBufType(type); + public UdtServerChannelConfig setAutoRead(boolean autoRead) { + super.setAutoRead(autoRead); return this; } } diff --git a/transport-udt/src/main/java/io/netty/channel/udt/UdtChannelConfig.java b/transport-udt/src/main/java/io/netty/channel/udt/UdtChannelConfig.java index 9bf0e50764..aa671933e6 100644 --- a/transport-udt/src/main/java/io/netty/channel/udt/UdtChannelConfig.java +++ b/transport-udt/src/main/java/io/netty/channel/udt/UdtChannelConfig.java @@ -21,6 +21,7 @@ import io.netty.buffer.ByteBufAllocator; import io.netty.channel.ChannelConfig; import io.netty.channel.ChannelException; import io.netty.channel.ChannelOption; +import io.netty.channel.RecvByteBufAllocator; /** * A {@link ChannelConfig} for a {@link UdtChannel}. @@ -119,6 +120,9 @@ public interface UdtChannelConfig extends ChannelConfig { @Override UdtChannelConfig setAllocator(ByteBufAllocator allocator); + @Override + UdtChannelConfig setRecvByteBufAllocator(RecvByteBufAllocator allocator); + @Override UdtChannelConfig setAutoRead(boolean autoRead); @@ -161,7 +165,4 @@ public interface UdtChannelConfig extends ChannelConfig { * Sets {@link OptionUDT#System_Send_Buffer_Size} */ UdtChannelConfig setSystemSendBufferSize(int size); - - @Override - UdtChannelConfig setDefaultHandlerByteBufType(ChannelHandlerByteBufType type); } diff --git a/transport-udt/src/main/java/io/netty/channel/udt/UdtServerChannelConfig.java b/transport-udt/src/main/java/io/netty/channel/udt/UdtServerChannelConfig.java index 4b0666fcfb..6b1625f7b0 100644 --- a/transport-udt/src/main/java/io/netty/channel/udt/UdtServerChannelConfig.java +++ b/transport-udt/src/main/java/io/netty/channel/udt/UdtServerChannelConfig.java @@ -21,6 +21,7 @@ import io.netty.buffer.ByteBufAllocator; import io.netty.channel.ChannelConfig; import io.netty.channel.ChannelException; import io.netty.channel.ChannelOption; +import io.netty.channel.RecvByteBufAllocator; /** * A {@link ChannelConfig} for a {@link UdtServerChannel}. @@ -53,6 +54,9 @@ public interface UdtServerChannelConfig extends UdtChannelConfig { @Override UdtServerChannelConfig setAllocator(ByteBufAllocator allocator); + @Override + UdtServerChannelConfig setRecvByteBufAllocator(RecvByteBufAllocator allocator); + @Override UdtServerChannelConfig setAutoRead(boolean autoRead); @@ -79,7 +83,4 @@ public interface UdtServerChannelConfig extends UdtChannelConfig { @Override UdtServerChannelConfig setSystemSendBufferSize(int size); - - @Override - UdtServerChannelConfig setDefaultHandlerByteBufType(ChannelHandlerByteBufType type); } diff --git a/transport-udt/src/main/java/io/netty/channel/udt/nio/NioUdtAcceptorChannel.java b/transport-udt/src/main/java/io/netty/channel/udt/nio/NioUdtAcceptorChannel.java index 9d247d3557..95ddff4339 100644 --- a/transport-udt/src/main/java/io/netty/channel/udt/nio/NioUdtAcceptorChannel.java +++ b/transport-udt/src/main/java/io/netty/channel/udt/nio/NioUdtAcceptorChannel.java @@ -17,8 +17,8 @@ package io.netty.channel.udt.nio; import com.barchart.udt.TypeUDT; import com.barchart.udt.nio.ServerSocketChannelUDT; -import io.netty.buffer.MessageBuf; import io.netty.channel.ChannelException; +import io.netty.channel.MessageList; import io.netty.channel.nio.AbstractNioMessageChannel; import io.netty.channel.udt.DefaultUdtServerChannelConfig; import io.netty.channel.udt.UdtServerChannel; @@ -95,8 +95,7 @@ public abstract class NioUdtAcceptorChannel extends AbstractNioMessageChannel } @Override - protected int doWriteMessages(final MessageBuf buf, - final boolean lastSpin) throws Exception { + protected int doWriteMessages(MessageList msg, int index, boolean lastSpin) throws Exception { throw new UnsupportedOperationException(); } diff --git a/transport-udt/src/main/java/io/netty/channel/udt/nio/NioUdtByteAcceptorChannel.java b/transport-udt/src/main/java/io/netty/channel/udt/nio/NioUdtByteAcceptorChannel.java index 185b3cb5fc..09fe795441 100644 --- a/transport-udt/src/main/java/io/netty/channel/udt/nio/NioUdtByteAcceptorChannel.java +++ b/transport-udt/src/main/java/io/netty/channel/udt/nio/NioUdtByteAcceptorChannel.java @@ -17,30 +17,27 @@ package io.netty.channel.udt.nio; import com.barchart.udt.TypeUDT; import com.barchart.udt.nio.SocketChannelUDT; -import io.netty.buffer.BufType; -import io.netty.buffer.MessageBuf; import io.netty.channel.ChannelMetadata; +import io.netty.channel.MessageList; /** * Byte Channel Acceptor for UDT Streams. */ public class NioUdtByteAcceptorChannel extends NioUdtAcceptorChannel { - private static final ChannelMetadata METADATA = new ChannelMetadata( - BufType.BYTE, false); + private static final ChannelMetadata METADATA = new ChannelMetadata(false); public NioUdtByteAcceptorChannel() { super(TypeUDT.STREAM); } @Override - protected int doReadMessages(final MessageBuf buf) throws Exception { + protected int doReadMessages(MessageList buf) throws Exception { final SocketChannelUDT channelUDT = javaChannel().accept(); if (channelUDT == null) { return 0; } else { - buf.add(new NioUdtByteConnectorChannel(this, channelUDT.socketUDT() - .id(), channelUDT)); + buf.add(new NioUdtByteConnectorChannel(this, channelUDT.socketUDT().id(), channelUDT)); return 1; } } @@ -49,5 +46,4 @@ public class NioUdtByteAcceptorChannel extends NioUdtAcceptorChannel { public ChannelMetadata metadata() { return METADATA; } - } diff --git a/transport-udt/src/main/java/io/netty/channel/udt/nio/NioUdtByteConnectorChannel.java b/transport-udt/src/main/java/io/netty/channel/udt/nio/NioUdtByteConnectorChannel.java index f2d82c6fd2..76eac99fec 100644 --- a/transport-udt/src/main/java/io/netty/channel/udt/nio/NioUdtByteConnectorChannel.java +++ b/transport-udt/src/main/java/io/netty/channel/udt/nio/NioUdtByteConnectorChannel.java @@ -17,11 +17,11 @@ package io.netty.channel.udt.nio; import com.barchart.udt.TypeUDT; import com.barchart.udt.nio.SocketChannelUDT; -import io.netty.buffer.BufType; import io.netty.buffer.ByteBuf; import io.netty.channel.Channel; import io.netty.channel.ChannelException; import io.netty.channel.ChannelMetadata; +import io.netty.channel.FileRegion; import io.netty.channel.nio.AbstractNioByteChannel; import io.netty.channel.udt.DefaultUdtChannelConfig; import io.netty.channel.udt.UdtChannel; @@ -44,8 +44,7 @@ public class NioUdtByteConnectorChannel extends AbstractNioByteChannel private static final InternalLogger logger = InternalLoggerFactory .getInstance(NioUdtByteConnectorChannel.class); - private static final ChannelMetadata METADATA = new ChannelMetadata( - BufType.BYTE, false); + private static final ChannelMetadata METADATA = new ChannelMetadata(false); private final UdtChannelConfig config; @@ -166,6 +165,11 @@ public class NioUdtByteConnectorChannel extends AbstractNioByteChannel return writtenBytes; } + @Override + protected long doWriteFileRegion(FileRegion region, boolean lastSpin) throws Exception { + throw new UnsupportedOperationException(); + } + @Override public boolean isActive() { final SocketChannelUDT channelUDT = javaChannel(); diff --git a/transport-udt/src/main/java/io/netty/channel/udt/nio/NioUdtMessageAcceptorChannel.java b/transport-udt/src/main/java/io/netty/channel/udt/nio/NioUdtMessageAcceptorChannel.java index 12c0e63a1e..0ccb785924 100644 --- a/transport-udt/src/main/java/io/netty/channel/udt/nio/NioUdtMessageAcceptorChannel.java +++ b/transport-udt/src/main/java/io/netty/channel/udt/nio/NioUdtMessageAcceptorChannel.java @@ -17,30 +17,27 @@ package io.netty.channel.udt.nio; import com.barchart.udt.TypeUDT; import com.barchart.udt.nio.SocketChannelUDT; -import io.netty.buffer.BufType; -import io.netty.buffer.MessageBuf; import io.netty.channel.ChannelMetadata; +import io.netty.channel.MessageList; /** * Message Channel Acceptor for UDT Datagrams. */ public class NioUdtMessageAcceptorChannel extends NioUdtAcceptorChannel { - private static final ChannelMetadata METADATA = new ChannelMetadata( - BufType.MESSAGE, false); + private static final ChannelMetadata METADATA = new ChannelMetadata(false); public NioUdtMessageAcceptorChannel() { super(TypeUDT.DATAGRAM); } @Override - protected int doReadMessages(final MessageBuf buf) throws Exception { + protected int doReadMessages(MessageList buf) throws Exception { final SocketChannelUDT channelUDT = javaChannel().accept(); if (channelUDT == null) { return 0; } else { - buf.add(new NioUdtMessageConnectorChannel(this, channelUDT - .socketUDT().id(), channelUDT)); + buf.add(new NioUdtMessageConnectorChannel(this, channelUDT.socketUDT().id(), channelUDT)); return 1; } } diff --git a/transport-udt/src/main/java/io/netty/channel/udt/nio/NioUdtMessageConnectorChannel.java b/transport-udt/src/main/java/io/netty/channel/udt/nio/NioUdtMessageConnectorChannel.java index c8cd60879a..c1fb1d39f5 100644 --- a/transport-udt/src/main/java/io/netty/channel/udt/nio/NioUdtMessageConnectorChannel.java +++ b/transport-udt/src/main/java/io/netty/channel/udt/nio/NioUdtMessageConnectorChannel.java @@ -17,12 +17,11 @@ package io.netty.channel.udt.nio; import com.barchart.udt.TypeUDT; import com.barchart.udt.nio.SocketChannelUDT; -import io.netty.buffer.BufType; import io.netty.buffer.ByteBuf; -import io.netty.buffer.MessageBuf; import io.netty.channel.Channel; import io.netty.channel.ChannelException; import io.netty.channel.ChannelMetadata; +import io.netty.channel.MessageList; import io.netty.channel.nio.AbstractNioMessageChannel; import io.netty.channel.udt.DefaultUdtChannelConfig; import io.netty.channel.udt.UdtChannel; @@ -48,8 +47,7 @@ public class NioUdtMessageConnectorChannel extends AbstractNioMessageChannel private static final InternalLogger logger = InternalLoggerFactory .getInstance(NioUdtMessageConnectorChannel.class); - private static final ChannelMetadata METADATA = new ChannelMetadata( - BufType.MESSAGE, false); + private static final ChannelMetadata METADATA = new ChannelMetadata(false); private final UdtChannelConfig config; @@ -143,7 +141,7 @@ public class NioUdtMessageConnectorChannel extends AbstractNioMessageChannel } @Override - protected int doReadMessages(final MessageBuf buf) throws Exception { + protected int doReadMessages(MessageList buf) throws Exception { final int maximumMessageSize = config.getReceiveBufferSize(); @@ -171,11 +169,9 @@ public class NioUdtMessageConnectorChannel extends AbstractNioMessageChannel } @Override - protected int doWriteMessages(final MessageBuf messageQueue, - final boolean lastSpin) throws Exception { - + protected int doWriteMessages(MessageList msgs, int index, boolean lastSpin) throws Exception { // expects a message - final UdtMessage message = (UdtMessage) messageQueue.peek(); + final UdtMessage message = (UdtMessage) msgs.get(index); final ByteBuf byteBuf = message.content(); @@ -208,14 +204,12 @@ public class NioUdtMessageConnectorChannel extends AbstractNioMessageChannel } // wrote the message queue completely - clear OP_WRITE. - if (messageQueue.isEmpty()) { + if (index + 1 == msgs.size()) { if ((interestOps & OP_WRITE) != 0) { key.interestOps(interestOps & ~OP_WRITE); } } - messageQueue.remove(); - message.release(); return 1; diff --git a/transport-udt/src/test/java/io/netty/test/udt/nio/NioUdtByteAcceptorChannelTest.java b/transport-udt/src/test/java/io/netty/test/udt/nio/NioUdtByteAcceptorChannelTest.java index 1910600346..260187c5d1 100644 --- a/transport-udt/src/test/java/io/netty/test/udt/nio/NioUdtByteAcceptorChannelTest.java +++ b/transport-udt/src/test/java/io/netty/test/udt/nio/NioUdtByteAcceptorChannelTest.java @@ -16,7 +16,6 @@ package io.netty.test.udt.nio; -import io.netty.buffer.BufType; import io.netty.channel.udt.nio.NioUdtByteAcceptorChannel; import org.junit.Test; @@ -29,6 +28,6 @@ public class NioUdtByteAcceptorChannelTest extends AbstractUdtTest { */ @Test public void metadata() throws Exception { - assertEquals(BufType.BYTE, new NioUdtByteAcceptorChannel().metadata().bufferType()); + assertEquals(false, new NioUdtByteAcceptorChannel().metadata().hasDisconnect()); } } diff --git a/transport-udt/src/test/java/io/netty/test/udt/nio/NioUdtByteConnectorChannelTest.java b/transport-udt/src/test/java/io/netty/test/udt/nio/NioUdtByteConnectorChannelTest.java index 45c197bc86..6426ca69ad 100644 --- a/transport-udt/src/test/java/io/netty/test/udt/nio/NioUdtByteConnectorChannelTest.java +++ b/transport-udt/src/test/java/io/netty/test/udt/nio/NioUdtByteConnectorChannelTest.java @@ -16,11 +16,10 @@ package io.netty.test.udt.nio; -import io.netty.buffer.BufType; import io.netty.channel.udt.nio.NioUdtByteConnectorChannel; import org.junit.Test; -import static org.junit.Assert.*; +import static org.junit.Assert.assertEquals; public class NioUdtByteConnectorChannelTest extends AbstractUdtTest { @@ -29,6 +28,6 @@ public class NioUdtByteConnectorChannelTest extends AbstractUdtTest { */ @Test public void metadata() throws Exception { - assertEquals(BufType.BYTE, new NioUdtByteConnectorChannel().metadata().bufferType()); + assertEquals(false, new NioUdtByteConnectorChannel().metadata().hasDisconnect()); } } diff --git a/transport-udt/src/test/java/io/netty/test/udt/nio/NioUdtByteRendezvousChannelTest.java b/transport-udt/src/test/java/io/netty/test/udt/nio/NioUdtByteRendezvousChannelTest.java index dd9fe080c5..cb41cbfeab 100644 --- a/transport-udt/src/test/java/io/netty/test/udt/nio/NioUdtByteRendezvousChannelTest.java +++ b/transport-udt/src/test/java/io/netty/test/udt/nio/NioUdtByteRendezvousChannelTest.java @@ -19,7 +19,6 @@ package io.netty.test.udt.nio; import com.yammer.metrics.Metrics; import com.yammer.metrics.core.Meter; import io.netty.bootstrap.Bootstrap; -import io.netty.buffer.BufType; import io.netty.channel.ChannelFuture; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.udt.nio.NioUdtByteRendezvousChannel; @@ -45,7 +44,7 @@ public class NioUdtByteRendezvousChannelTest extends AbstractUdtTest { */ @Test public void metadata() throws Exception { - assertEquals(BufType.BYTE, new NioUdtByteRendezvousChannel().metadata().bufferType()); + assertEquals(false, new NioUdtByteRendezvousChannel().metadata().hasDisconnect()); } /** diff --git a/transport-udt/src/test/java/io/netty/test/udt/nio/NioUdtMessageAcceptorChannelTest.java b/transport-udt/src/test/java/io/netty/test/udt/nio/NioUdtMessageAcceptorChannelTest.java index e7bdfe8089..a3099a8be1 100644 --- a/transport-udt/src/test/java/io/netty/test/udt/nio/NioUdtMessageAcceptorChannelTest.java +++ b/transport-udt/src/test/java/io/netty/test/udt/nio/NioUdtMessageAcceptorChannelTest.java @@ -16,7 +16,6 @@ package io.netty.test.udt.nio; -import io.netty.buffer.BufType; import io.netty.channel.udt.nio.NioUdtMessageAcceptorChannel; import org.junit.Test; @@ -29,6 +28,6 @@ public class NioUdtMessageAcceptorChannelTest extends AbstractUdtTest { */ @Test public void metadata() throws Exception { - assertEquals(BufType.MESSAGE, new NioUdtMessageAcceptorChannel().metadata().bufferType()); + assertEquals(false, new NioUdtMessageAcceptorChannel().metadata().hasDisconnect()); } } diff --git a/transport-udt/src/test/java/io/netty/test/udt/nio/NioUdtMessageConnectorChannelTest.java b/transport-udt/src/test/java/io/netty/test/udt/nio/NioUdtMessageConnectorChannelTest.java index 4d5d7fe473..8c2e2df588 100644 --- a/transport-udt/src/test/java/io/netty/test/udt/nio/NioUdtMessageConnectorChannelTest.java +++ b/transport-udt/src/test/java/io/netty/test/udt/nio/NioUdtMessageConnectorChannelTest.java @@ -16,7 +16,6 @@ package io.netty.test.udt.nio; -import io.netty.buffer.BufType; import io.netty.channel.udt.nio.NioUdtMessageConnectorChannel; import org.junit.Test; @@ -29,6 +28,6 @@ public class NioUdtMessageConnectorChannelTest extends AbstractUdtTest { */ @Test public void metadata() throws Exception { - assertEquals(BufType.MESSAGE, new NioUdtMessageConnectorChannel().metadata().bufferType()); + assertEquals(false, new NioUdtMessageConnectorChannel().metadata().hasDisconnect()); } } diff --git a/transport-udt/src/test/java/io/netty/test/udt/nio/NioUdtMessageRendezvousChannelTest.java b/transport-udt/src/test/java/io/netty/test/udt/nio/NioUdtMessageRendezvousChannelTest.java index 073943eb0d..ec99de1e6a 100644 --- a/transport-udt/src/test/java/io/netty/test/udt/nio/NioUdtMessageRendezvousChannelTest.java +++ b/transport-udt/src/test/java/io/netty/test/udt/nio/NioUdtMessageRendezvousChannelTest.java @@ -19,7 +19,6 @@ package io.netty.test.udt.nio; import com.yammer.metrics.Metrics; import com.yammer.metrics.core.Meter; import io.netty.bootstrap.Bootstrap; -import io.netty.buffer.BufType; import io.netty.channel.ChannelFuture; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.udt.nio.NioUdtMessageRendezvousChannel; @@ -45,7 +44,7 @@ public class NioUdtMessageRendezvousChannelTest extends AbstractUdtTest { */ @Test public void metadata() throws Exception { - assertEquals(BufType.MESSAGE, new NioUdtMessageRendezvousChannel().metadata().bufferType()); + assertEquals(false, new NioUdtMessageRendezvousChannel().metadata().hasDisconnect()); } /** diff --git a/transport-udt/src/test/java/io/netty/test/udt/util/EchoByteHandler.java b/transport-udt/src/test/java/io/netty/test/udt/util/EchoByteHandler.java index ebaed66ea4..ab839cd103 100644 --- a/transport-udt/src/test/java/io/netty/test/udt/util/EchoByteHandler.java +++ b/transport-udt/src/test/java/io/netty/test/udt/util/EchoByteHandler.java @@ -20,9 +20,8 @@ import com.yammer.metrics.core.Meter; import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.ChannelHandlerUtil; -import io.netty.channel.ChannelInboundByteHandlerAdapter; -import io.netty.channel.ChannelOption; +import io.netty.channel.ChannelInboundHandlerAdapter; +import io.netty.channel.MessageList; import io.netty.channel.udt.nio.NioUdtProvider; import io.netty.util.internal.logging.InternalLogger; import io.netty.util.internal.logging.InternalLoggerFactory; @@ -32,7 +31,7 @@ import io.netty.util.internal.logging.InternalLoggerFactory; * traffic between the echo client and server by sending the first message to * the server on activation. */ -public class EchoByteHandler extends ChannelInboundByteHandlerAdapter { +public class EchoByteHandler extends ChannelInboundHandlerAdapter { private static final InternalLogger log = InternalLoggerFactory.getInstance(EchoByteHandler.class); @@ -62,25 +61,18 @@ public class EchoByteHandler extends ChannelInboundByteHandlerAdapter { .toStringOptions()); ctx.write(message); - - ctx.flush(); } @Override - public void inboundBufferUpdated(final ChannelHandlerContext ctx, - final ByteBuf in) { - - if (meter != null) { - meter.mark(in.readableBytes()); + public void messageReceived(ChannelHandlerContext ctx, MessageList msgs) throws Exception { + for (int i = 0; i < msgs.size(); i ++) { + ByteBuf buf = (ByteBuf) msgs.get(i); + if (meter != null) { + meter.mark(buf.readableBytes()); + } + buf.retain(); } - - final ByteBuf out = ctx.nextOutboundByteBuffer(); - - out.discardReadBytes(); // FIXME - - out.writeBytes(in); - - ctx.flush(); + ctx.write(msgs); } @Override @@ -91,10 +83,4 @@ public class EchoByteHandler extends ChannelInboundByteHandlerAdapter { ctx.close(); } - - @Override - public ByteBuf newInboundBuffer(final ChannelHandlerContext ctx) throws Exception { - return ChannelHandlerUtil.allocate(ctx, - ctx.channel().config().getOption(ChannelOption.SO_RCVBUF)); - } } diff --git a/transport-udt/src/test/java/io/netty/test/udt/util/EchoMessageHandler.java b/transport-udt/src/test/java/io/netty/test/udt/util/EchoMessageHandler.java index 7fa2c27f3f..5ed41a28f4 100644 --- a/transport-udt/src/test/java/io/netty/test/udt/util/EchoMessageHandler.java +++ b/transport-udt/src/test/java/io/netty/test/udt/util/EchoMessageHandler.java @@ -18,10 +18,10 @@ package io.netty.test.udt.util; import com.yammer.metrics.core.Meter; import io.netty.buffer.ByteBuf; -import io.netty.buffer.MessageBuf; import io.netty.buffer.Unpooled; import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.ChannelInboundMessageHandlerAdapter; +import io.netty.channel.ChannelInboundHandlerAdapter; +import io.netty.channel.MessageList; import io.netty.channel.udt.UdtMessage; import io.netty.channel.udt.nio.NioUdtProvider; import io.netty.util.internal.logging.InternalLogger; @@ -32,8 +32,7 @@ import io.netty.util.internal.logging.InternalLoggerFactory; * between the echo peers by sending the first message to the other peer on * activation. */ -public class EchoMessageHandler extends - ChannelInboundMessageHandlerAdapter { +public class EchoMessageHandler extends ChannelInboundHandlerAdapter { private static final InternalLogger log = InternalLoggerFactory.getInstance(EchoMessageHandler.class); @@ -61,11 +60,7 @@ public class EchoMessageHandler extends log.info("ECHO active {}", NioUdtProvider.socketUDT(ctx.channel()) .toStringOptions()); - - final MessageBuf out = ctx.nextOutboundMessageBuffer(); - - out.add(message); - ctx.flush(); + ctx.write(message); } @Override @@ -75,18 +70,13 @@ public class EchoMessageHandler extends } @Override - public void messageReceived(final ChannelHandlerContext ctx, final UdtMessage message) throws Exception { - - final ByteBuf byteBuf = message.content(); - - if (meter != null) { - meter.mark(byteBuf.readableBytes()); + public void messageReceived(ChannelHandlerContext ctx, MessageList msgs) throws Exception { + for (int i = 0; i < msgs.size(); i ++) { + UdtMessage udtMsg = (UdtMessage) msgs.get(i); + if (meter != null) { + meter.mark(udtMsg.content().readableBytes()); + } } - - final MessageBuf out = ctx.nextOutboundMessageBuffer(); - - message.retain(); - out.add(message); - ctx.flush(); + ctx.write(msgs); } } diff --git a/transport/pom.xml b/transport/pom.xml index 381a660b37..5f11431823 100644 --- a/transport/pom.xml +++ b/transport/pom.xml @@ -20,7 +20,7 @@ io.netty netty-parent - 4.0.0.Final-SNAPSHOT + 4.0.0.CR4-SNAPSHOT netty-transport diff --git a/transport/src/main/java/io/netty/bootstrap/ServerBootstrap.java b/transport/src/main/java/io/netty/bootstrap/ServerBootstrap.java index 9835c15ea2..48a3464ada 100644 --- a/transport/src/main/java/io/netty/bootstrap/ServerBootstrap.java +++ b/transport/src/main/java/io/netty/bootstrap/ServerBootstrap.java @@ -15,18 +15,16 @@ */ package io.netty.bootstrap; -import io.netty.buffer.MessageBuf; -import io.netty.buffer.Unpooled; import io.netty.channel.Channel; import io.netty.channel.ChannelConfig; import io.netty.channel.ChannelHandler; import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.ChannelInboundMessageHandler; +import io.netty.channel.ChannelInboundHandlerAdapter; import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelOption; import io.netty.channel.ChannelPipeline; -import io.netty.channel.ChannelStateHandlerAdapter; import io.netty.channel.EventLoopGroup; +import io.netty.channel.MessageList; import io.netty.channel.ServerChannel; import io.netty.channel.socket.SocketChannel; import io.netty.util.AttributeKey; @@ -212,8 +210,7 @@ public final class ServerBootstrap extends AbstractBootstrap { + private static class ServerBootstrapAcceptor extends ChannelInboundHandlerAdapter { private final EventLoopGroup childGroup; private final ChannelHandler childHandler; @@ -230,21 +227,12 @@ public final class ServerBootstrap extends AbstractBootstrap newInboundBuffer(ChannelHandlerContext ctx) throws Exception { - return Unpooled.messageBuffer(); - } - @Override @SuppressWarnings("unchecked") - public void inboundBufferUpdated(ChannelHandlerContext ctx) { - MessageBuf in = ctx.inboundMessageBuffer(); - for (;;) { - Channel child = in.poll(); - if (child == null) { - break; - } - + public void messageReceived(ChannelHandlerContext ctx, MessageList msgs) { + int size = msgs.size(); + for (int i = 0; i < size; i ++) { + Channel child = (Channel) msgs.get(i); child.pipeline().addLast(childHandler); for (Entry, Object> e: childOptions) { diff --git a/transport/src/main/java/io/netty/channel/AbstractChannel.java b/transport/src/main/java/io/netty/channel/AbstractChannel.java index d0d65ef920..2f7e9d6695 100644 --- a/transport/src/main/java/io/netty/channel/AbstractChannel.java +++ b/transport/src/main/java/io/netty/channel/AbstractChannel.java @@ -15,10 +15,9 @@ */ package io.netty.channel; -import io.netty.buffer.BufType; import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBufAllocator; -import io.netty.buffer.MessageBuf; +import io.netty.buffer.ByteBufHolder; import io.netty.util.DefaultAttributeMap; import io.netty.util.internal.PlatformDependent; import io.netty.util.internal.logging.InternalLogger; @@ -78,13 +77,12 @@ public abstract class AbstractChannel extends DefaultAttributeMap implements Cha private final Integer id; private final Unsafe unsafe; private final DefaultChannelPipeline pipeline; + private final ChannelOutboundBuffer outboundBuffer = new ChannelOutboundBuffer(this); private final ChannelFuture succeededFuture = new SucceededChannelFuture(this, null); private final VoidChannelPromise voidPromise = new VoidChannelPromise(this, true); private final VoidChannelPromise unsafeVoidPromise = new VoidChannelPromise(this, false); private final CloseFuture closeFuture = new CloseFuture(this); - protected final ChannelFlushPromiseNotifier flushFutureNotifier = new ChannelFlushPromiseNotifier(); - private volatile SocketAddress localAddress; private volatile SocketAddress remoteAddress; private volatile EventLoop eventLoop; @@ -93,7 +91,6 @@ public abstract class AbstractChannel extends DefaultAttributeMap implements Cha private ClosedChannelException closedChannelException; private boolean inFlushNow; private boolean flushNowPending; - private FlushTask flushTaskInProgress; /** Cache for the string representation of this channel */ private boolean strValActive; @@ -134,6 +131,11 @@ public abstract class AbstractChannel extends DefaultAttributeMap implements Cha }); } + @Override + public boolean isWritable() { + return outboundBuffer.getWritable(); + } + @Override public final Integer id() { return id; @@ -238,13 +240,13 @@ public abstract class AbstractChannel extends DefaultAttributeMap implements Cha } @Override - public ChannelFuture flush() { - return pipeline.flush(); + public ChannelFuture write(Object msg) { + return pipeline.write(msg); } @Override - public ChannelFuture write(Object message) { - return pipeline.write(message); + public ChannelFuture write(MessageList msgs) { + return pipeline.write(msgs); } @Override @@ -277,30 +279,19 @@ public abstract class AbstractChannel extends DefaultAttributeMap implements Cha return pipeline.deregister(promise); } - @Override - public ByteBuf outboundByteBuffer() { - return pipeline.outboundByteBuffer(); - } - - @Override - @SuppressWarnings("unchecked") - public MessageBuf outboundMessageBuffer() { - return pipeline.outboundMessageBuffer(); - } - @Override public void read() { pipeline.read(); } @Override - public ChannelFuture flush(ChannelPromise promise) { - return pipeline.flush(promise); + public ChannelFuture write(Object msg, ChannelPromise promise) { + return pipeline.write(msg, promise); } @Override - public ChannelFuture write(Object message, ChannelPromise promise) { - return pipeline.write(message, promise); + public ChannelFuture write(MessageList msgs, ChannelPromise promise) { + return pipeline.write(msgs, promise); } @Override @@ -333,45 +324,6 @@ public abstract class AbstractChannel extends DefaultAttributeMap implements Cha return unsafe; } - @Override - public ChannelFuture sendFile(FileRegion region) { - return pipeline.sendFile(region); - } - - @Override - public ChannelFuture sendFile(FileRegion region, ChannelPromise promise) { - return pipeline.sendFile(region, promise); - } - - // 0 - not expanded because the buffer is writable - // 1 - expanded because the buffer was not writable - // 2 - could not expand because the buffer was at its maximum although the buffer is not writable. - protected static int expandReadBuffer(ByteBuf byteBuf) { - final int writerIndex = byteBuf.writerIndex(); - final int capacity = byteBuf.capacity(); - if (capacity != writerIndex) { - return 0; - } - - final int maxCapacity = byteBuf.maxCapacity(); - if (capacity == maxCapacity) { - return 2; - } - - // FIXME: Magic number - final int increment = 4096; - - if (writerIndex + increment > maxCapacity) { - // Expand to maximum capacity. - byteBuf.capacity(maxCapacity); - } else { - // Expand by the increment. - byteBuf.ensureWritable(increment); - } - - return 1; - } - /** * Create a new {@link AbstractUnsafe} instance which will be used for the life-time of the {@link Channel} */ @@ -443,164 +395,19 @@ public abstract class AbstractChannel extends DefaultAttributeMap implements Cha return voidPromise; } - /** - * Task which will flush a {@link FileRegion} - */ - protected final class FlushTask { - private final FileRegion region; - private final ChannelPromise promise; - private FlushTask next; - private final AbstractUnsafe unsafe; - - FlushTask(AbstractUnsafe unsafe, FileRegion region, ChannelPromise promise) { - this.region = region; - this.promise = promise; - this.unsafe = unsafe; - } - - /** - * Mark the task as success. Multiple calls if this will throw a {@link IllegalStateException}. - * - * This also will call {@link FileRegion#release()}. - */ - public void setSuccess() { - if (eventLoop().inEventLoop()) { - promise.setSuccess(); - complete(); - } else { - eventLoop().execute(new Runnable() { - @Override - public void run() { - setSuccess(); - } - }); - } - } - - /** - * Notify the task of progress in transfer of the {@link FileRegion}. - */ - public void setProgress(long progress) { - if (promise instanceof ChannelProgressivePromise) { - ((ChannelProgressivePromise) promise).setProgress(progress, region.count()); - } - } - - /** - * Mark the task as failure. Multiple calls if this will throw a {@link IllegalStateException}. - * - * This also will call {@link FileRegion#release()}. - */ - public void setFailure(final Throwable cause) { - if (eventLoop().inEventLoop()) { - promise.setFailure(cause); - complete(); - } else { - eventLoop().execute(new Runnable() { - @Override - public void run() { - setFailure(cause); - } - }); - } - } - - /** - * Return the {@link FileRegion} which should be flushed - */ - public FileRegion region() { - return region; - } - - private void complete() { - region.release(); - flushTaskInProgress = next; - if (next != null) { - try { - FileRegion region = next.region; - if (region == null) { - // no region present means the next flush task was to directly flush - // the outbound buffer - unsafe.flushNotifierAndFlush(next.promise); - } else { - // flush the region now - doFlushFileRegion(next); - } - } catch (Throwable cause) { - next.promise.setFailure(cause); - } - } else { - // notify the flush futures - flushFutureNotifier.notifyFlushFutures(); - } - } - } - /** * {@link Unsafe} implementation which sub-classes must extend and use. */ protected abstract class AbstractUnsafe implements Unsafe { - private final Runnable beginReadTask = new Runnable() { - @Override - public void run() { - beginRead(); - } - }; - private final Runnable flushLaterTask = new Runnable() { @Override public void run() { flushNowPending = false; - flush(voidPromise()); + flush(); } }; - @Override - public final void sendFile(final FileRegion region, final ChannelPromise promise) { - if (outboundBufSize() > 0) { - flushNotifier(newPromise()).addListener(new ChannelFutureListener() { - @Override - public void operationComplete(ChannelFuture cf) throws Exception { - sendFile0(region, promise); - } - }); - } else { - // nothing pending try to send the fileRegion now! - sendFile0(region, promise); - } - } - - private void sendFile0(FileRegion region, ChannelPromise promise) { - FlushTask task = flushTaskInProgress; - if (task == null) { - flushTaskInProgress = task = new FlushTask(this, region, promise); - try { - // the first FileRegion to flush so trigger it now! - doFlushFileRegion(task); - } catch (Throwable cause) { - region.release(); - promise.setFailure(cause); - } - return; - } - - for (;;) { - FlushTask next = task.next; - if (next == null) { - break; - } - task = next; - } - // there is something that needs to get flushed first so add it as next in the chain - task.next = new FlushTask(this, region, promise); - } - - @Override - public final ChannelHandlerContext headContext() { - return pipeline.head; - } - @Override public final SocketAddress localAddress() { return localAddress0(); @@ -745,7 +552,10 @@ public abstract class AbstractChannel extends DefaultAttributeMap implements Cha closedChannelException = new ClosedChannelException(); } - flushFutureNotifier.notifyFlushFutures(closedChannelException); + // fail all queued messages + if (outboundBuffer.next()) { + outboundBuffer.fail(closedChannelException); + } if (wasActive && !isActive()) { invokeLater(new Runnable() { @@ -827,48 +637,12 @@ public abstract class AbstractChannel extends DefaultAttributeMap implements Cha } @Override - public void flush(final ChannelPromise promise) { - FlushTask task = flushTaskInProgress; - if (task == null) { - flushNotifierAndFlush(promise); - } else { - // loop over the tasks to find the last one - for (;;) { - FlushTask t = task.next; - if (t == null) { - break; - } - task = t.next; - } - task.next = new FlushTask(this, null, promise); - } + public void write(MessageList msgs, ChannelPromise promise) { + outboundBuffer.add(msgs, promise); + flush(); } - private void flushNotifierAndFlush(ChannelPromise promise) { - flushNotifier(promise); - flush0(); - } - - private int outboundBufSize() { - final int bufSize; - final ChannelHandlerContext ctx = headContext(); - if (metadata().bufferType() == BufType.BYTE) { - bufSize = ctx.outboundByteBuffer().readableBytes(); - } else { - bufSize = ctx.outboundMessageBuffer().size(); - } - return bufSize; - } - - private ChannelFuture flushNotifier(ChannelPromise promise) { - // Append flush future to the notification list. - if (promise != voidPromise) { - flushFutureNotifier.add(promise, outboundBufSize()); - } - return promise; - } - - private void flush0() { + private void flush() { if (!inFlushNow) { // Avoid re-entrance try { // Flush immediately only when there's no pending flush. @@ -878,10 +652,8 @@ public abstract class AbstractChannel extends DefaultAttributeMap implements Cha flushNow(); } } catch (Throwable t) { - flushFutureNotifier.notifyFlushFutures(t); - if (t instanceof IOException) { - close(voidPromise()); - } + outboundBuffer.fail(t); + close(voidPromise()); } } else { if (!flushNowPending) { @@ -890,47 +662,55 @@ public abstract class AbstractChannel extends DefaultAttributeMap implements Cha } } } + @Override public final void flushNow() { - if (inFlushNow || flushTaskInProgress != null) { + if (inFlushNow) { return; } inFlushNow = true; - ChannelHandlerContext ctx = headContext(); - Throwable cause = null; + final ChannelOutboundBuffer outboundBuffer = AbstractChannel.this.outboundBuffer; try { - if (metadata().bufferType() == BufType.BYTE) { - ByteBuf out = ctx.outboundByteBuffer(); - int oldSize = out.readableBytes(); - try { - doFlushByteBuffer(out); - } catch (Throwable t) { - cause = t; - } finally { - int delta = oldSize - out.readableBytes(); - out.discardSomeReadBytes(); - flushFutureNotifier.increaseWriteCounter(delta); + for (;;) { + ChannelPromise promise = outboundBuffer.currentPromise; + if (promise == null) { + if (!outboundBuffer.next()) { + break; + } + promise = outboundBuffer.currentPromise; } - } else { - MessageBuf out = ctx.outboundMessageBuffer(); - int oldSize = out.size(); - try { - doFlushMessageBuffer(out); - } catch (Throwable t) { - cause = t; - } finally { - flushFutureNotifier.increaseWriteCounter(oldSize - out.size()); + + MessageList messages = outboundBuffer.currentMessages; + int messageIndex = outboundBuffer.currentMessageIndex; + int messageCount = messages.size(); + if (messageCount == 0) { + messages.recycle(); + promise.trySuccess(); + if (!outboundBuffer.next()) { + break; + } else { + continue; + } + } + + int writtenMessages = doWrite(messages, messageIndex); + outboundBuffer.currentMessageIndex = messageIndex += writtenMessages; + if (messageIndex >= messageCount) { + messages.recycle(); + promise.trySuccess(); + if (!outboundBuffer.next()) { + break; + } + } else { + // Could not flush the current write request completely. Try again later. + break; } } - - if (cause == null) { - flushFutureNotifier.notifyFlushFutures(); - } else { - flushFutureNotifier.notifyFlushFutures(cause); - if (cause instanceof IOException) { - close(voidPromise()); - } + } catch (Throwable t) { + outboundBuffer.fail(t); + if (t instanceof IOException) { + close(voidPromise()); } } finally { inFlushNow = false; @@ -1042,37 +822,33 @@ public abstract class AbstractChannel extends DefaultAttributeMap implements Cha * Flush the content of the given {@link ByteBuf} to the remote peer. * * Sub-classes may override this as this implementation will just thrown an {@link UnsupportedOperationException} - */ - protected void doFlushByteBuffer(ByteBuf buf) throws Exception { - throw new UnsupportedOperationException(); - } - - /** - * Flush the content of the given {@link MessageBuf} to the remote peer. * - * Sub-classes may override this as this implementation will just thrown an {@link UnsupportedOperationException} + * @return the number of written messages */ - protected void doFlushMessageBuffer(MessageBuf buf) throws Exception { - throw new UnsupportedOperationException(); - } + protected abstract int doWrite(MessageList msgs, int index) throws Exception; - /** - * Flush the content of the given {@link FlushTask} to the remote peer. - * - * Sub-classes may override this as this implementation will just thrown an {@link UnsupportedOperationException} - */ - protected void doFlushFileRegion(FlushTask task) throws Exception { - throw new UnsupportedOperationException(); - } - - protected static void checkEOF(FileRegion region, long writtenBytes) throws IOException { - if (writtenBytes < region.count()) { + protected static void checkEOF(FileRegion region) throws IOException { + if (region.transfered() < region.count()) { throw new EOFException("Expected to be able to write " + region.count() + " bytes, but only wrote " - + writtenBytes); + + region.transfered()); } } + /** + * Calculate the number of bytes a message takes up in memory. Sub-classes may override this if they use different + * messages then {@link ByteBuf} or {@link ByteBufHolder}. If the size can not be calculated 0 should be returned. + */ + protected int calculateMessageSize(Object message) { + if (message instanceof ByteBuf) { + return ((ByteBuf) message).readableBytes(); + } + if (message instanceof ByteBufHolder) { + return ((ByteBufHolder) message).content().readableBytes(); + } + return 0; + } + /** * Return {@code true} if a flush to the {@link Channel} is currently pending. */ diff --git a/transport/src/main/java/io/netty/channel/AbstractServerChannel.java b/transport/src/main/java/io/netty/channel/AbstractServerChannel.java index 12d5181e1f..9334aa676f 100755 --- a/transport/src/main/java/io/netty/channel/AbstractServerChannel.java +++ b/transport/src/main/java/io/netty/channel/AbstractServerChannel.java @@ -15,9 +15,7 @@ */ package io.netty.channel; -import io.netty.buffer.BufType; -import io.netty.buffer.ByteBuf; -import io.netty.buffer.MessageBuf; +import io.netty.buffer.ByteBufUtil; import java.net.SocketAddress; @@ -27,13 +25,13 @@ import java.net.SocketAddress; *
    *
  • {@link #connect(SocketAddress, ChannelPromise)}
  • *
  • {@link #disconnect(ChannelPromise)}
  • - *
  • {@link #flush(ChannelPromise)}
  • + *
  • {@link ChannelOutboundInvoker#write(Object, ChannelPromise)}
  • *
  • and the shortcut methods which calls the methods mentioned above *
*/ public abstract class AbstractServerChannel extends AbstractChannel implements ServerChannel { - private static final ChannelMetadata METADATA = new ChannelMetadata(BufType.MESSAGE, false); + private static final ChannelMetadata METADATA = new ChannelMetadata(false); /** * Creates a new instance. @@ -42,18 +40,6 @@ public abstract class AbstractServerChannel extends AbstractChannel implements S super(null, id); } - @Override - public ByteBuf outboundByteBuffer() { - throw new NoSuchBufferException(String.format( - "%s does not have an outbound buffer.", ServerChannel.class.getSimpleName())); - } - - @Override - public MessageBuf outboundMessageBuffer() { - throw new NoSuchBufferException(String.format( - "%s does not have an outbound buffer.", ServerChannel.class.getSimpleName())); - } - @Override public ChannelMetadata metadata() { return METADATA; @@ -84,22 +70,28 @@ public abstract class AbstractServerChannel extends AbstractChannel implements S return new DefaultServerUnsafe(); } + @Override + protected int doWrite(MessageList msgs, int index) throws Exception { + throw new UnsupportedOperationException(); + } + private final class DefaultServerUnsafe extends AbstractUnsafe { @Override - public void flush(final ChannelPromise future) { - reject(future); + public void write(MessageList msgs, ChannelPromise promise) { + reject(promise); + int size = msgs.size(); + for (int i = 0; i < size; i ++) { + ByteBufUtil.release(msgs.get(i)); + } } @Override - public void connect( - final SocketAddress remoteAddress, final SocketAddress localAddress, - final ChannelPromise future) { - reject(future); + public void connect(SocketAddress remoteAddress, SocketAddress localAddress, ChannelPromise promise) { + reject(promise); } - private void reject(ChannelPromise future) { - Exception cause = new UnsupportedOperationException(); - future.setFailure(cause); + private void reject(ChannelPromise promise) { + promise.setFailure(new UnsupportedOperationException()); } } } diff --git a/transport/src/main/java/io/netty/channel/AdaptiveRecvByteBufAllocator.java b/transport/src/main/java/io/netty/channel/AdaptiveRecvByteBufAllocator.java new file mode 100644 index 0000000000..4c123840b0 --- /dev/null +++ b/transport/src/main/java/io/netty/channel/AdaptiveRecvByteBufAllocator.java @@ -0,0 +1,194 @@ +/* + * Copyright 2012 The Netty Project + * + * The Netty Project licenses this file to you under the Apache License, + * version 2.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +package io.netty.channel; + +import io.netty.buffer.ByteBuf; +import io.netty.buffer.ByteBufAllocator; + +import java.util.ArrayList; +import java.util.List; + +/** + * The {@link RecvByteBufAllocator} that automatically increases and + * decreases the predicted buffer size on feed back. + *

+ * It gradually increases the expected number of readable bytes if the previous + * read fully filled the allocated buffer. It gradually decreases the expected + * number of readable bytes if the read operation was not able to fill a certain + * amount of the allocated buffer two times consecutively. Otherwise, it keeps + * returning the same prediction. + */ +public class AdaptiveRecvByteBufAllocator implements RecvByteBufAllocator { + + static final int DEFAULT_MINIMUM = 64; + static final int DEFAULT_INITIAL = 1024; + static final int DEFAULT_MAXIMUM = 65536; + + private static final int INDEX_INCREMENT = 4; + private static final int INDEX_DECREMENT = 1; + + private static final int[] SIZE_TABLE; + + static { + List sizeTable = new ArrayList(); + for (int i = 1; i <= 8; i ++) { + sizeTable.add(i); + } + + for (int i = 4; i < 32; i ++) { + long v = 1L << i; + long inc = v >>> 4; + v -= inc << 3; + + for (int j = 0; j < 8; j ++) { + v += inc; + if (v > Integer.MAX_VALUE) { + sizeTable.add(Integer.MAX_VALUE); + } else { + sizeTable.add((int) v); + } + } + } + + SIZE_TABLE = new int[sizeTable.size()]; + for (int i = 0; i < SIZE_TABLE.length; i ++) { + SIZE_TABLE[i] = sizeTable.get(i); + } + } + + public static final AdaptiveRecvByteBufAllocator DEFAULT = new AdaptiveRecvByteBufAllocator(); + + private static int getSizeTableIndex(final int size) { + if (size <= 16) { + return size - 1; + } + + int bits = 0; + int v = size; + do { + v >>>= 1; + bits ++; + } while (v != 0); + + final int baseIdx = bits << 3; + final int startIdx = baseIdx - 18; + final int endIdx = baseIdx - 25; + + for (int i = startIdx; i >= endIdx; i --) { + if (size >= SIZE_TABLE[i]) { + return i; + } + } + + throw new Error("shouldn't reach here; please file a bug report."); + } + + private static final class HandleImpl implements Handle { + private final int minIndex; + private final int maxIndex; + private int index; + private int nextReceiveBufferSize; + private boolean decreaseNow; + + HandleImpl(int minIndex, int maxIndex, int initial) { + this.minIndex = minIndex; + this.maxIndex = maxIndex; + + index = getSizeTableIndex(initial); + nextReceiveBufferSize = SIZE_TABLE[index]; + } + + @Override + public ByteBuf allocate(ByteBufAllocator alloc) { + return alloc.ioBuffer(nextReceiveBufferSize); + } + + @Override + public int guess() { + return nextReceiveBufferSize; + } + + @Override + public void record(int actualReadBytes) { + if (actualReadBytes <= SIZE_TABLE[Math.max(0, index - INDEX_DECREMENT - 1)]) { + if (decreaseNow) { + index = Math.max(index - INDEX_DECREMENT, minIndex); + nextReceiveBufferSize = SIZE_TABLE[index]; + decreaseNow = false; + } else { + decreaseNow = true; + } + } else if (actualReadBytes >= nextReceiveBufferSize) { + index = Math.min(index + INDEX_INCREMENT, maxIndex); + nextReceiveBufferSize = SIZE_TABLE[index]; + decreaseNow = false; + } + } + } + + private final int minIndex; + private final int maxIndex; + private final int initial; + + /** + * Creates a new predictor with the default parameters. With the default + * parameters, the expected buffer size starts from {@code 1024}, does not + * go down below {@code 64}, and does not go up above {@code 65536}. + */ + private AdaptiveRecvByteBufAllocator() { + this(DEFAULT_MINIMUM, DEFAULT_INITIAL, DEFAULT_MAXIMUM); + } + + /** + * Creates a new predictor with the specified parameters. + * + * @param minimum the inclusive lower bound of the expected buffer size + * @param initial the initial buffer size when no feed back was received + * @param maximum the inclusive upper bound of the expected buffer size + */ + public AdaptiveRecvByteBufAllocator(int minimum, int initial, int maximum) { + if (minimum <= 0) { + throw new IllegalArgumentException("minimum: " + minimum); + } + if (initial < minimum) { + throw new IllegalArgumentException("initial: " + initial); + } + if (maximum < initial) { + throw new IllegalArgumentException("maximum: " + maximum); + } + + int minIndex = getSizeTableIndex(minimum); + if (SIZE_TABLE[minIndex] < minimum) { + this.minIndex = minIndex + 1; + } else { + this.minIndex = minIndex; + } + + int maxIndex = getSizeTableIndex(maximum); + if (SIZE_TABLE[maxIndex] > maximum) { + this.maxIndex = maxIndex - 1; + } else { + this.maxIndex = maxIndex; + } + + this.initial = initial; + } + + @Override + public Handle newHandle() { + return new HandleImpl(minIndex, maxIndex, initial); + } +} diff --git a/transport/src/main/java/io/netty/channel/Channel.java b/transport/src/main/java/io/netty/channel/Channel.java index a8612ce462..f50a42ee76 100755 --- a/transport/src/main/java/io/netty/channel/Channel.java +++ b/transport/src/main/java/io/netty/channel/Channel.java @@ -15,8 +15,6 @@ */ package io.netty.channel; -import io.netty.buffer.ByteBuf; -import io.netty.buffer.MessageBuf; import io.netty.channel.socket.DatagramChannel; import io.netty.channel.socket.DatagramPacket; import io.netty.channel.socket.ServerSocketChannel; @@ -113,22 +111,6 @@ public interface Channel extends AttributeMap, ChannelOutboundInvoker, ChannelPr */ ChannelMetadata metadata(); - /** - * Return the last {@link ByteBuf} of the {@link ChannelPipeline} which belongs to this {@link Channel}. - * - * This method may throw an {@link NoSuchBufferException} if you try to access this buffer and the - * {@link ChannelPipeline} does not contain any {@link ByteBuf}. - */ - ByteBuf outboundByteBuffer(); - - /** - * Return the last {@link MessageBuf} of the {@link ChannelPipeline} which belongs to this {@link Channel}. - * - * This method may throw an {@link NoSuchBufferException} if you try to access this buffer and the - * {@link ChannelPipeline} does not contain any {@link MessageBuf}. - */ - MessageBuf outboundMessageBuffer(); - /** * Returns the local address where this channel is bound to. The returned * {@link SocketAddress} is supposed to be down-cast into more concrete @@ -162,6 +144,14 @@ public interface Channel extends AttributeMap, ChannelOutboundInvoker, ChannelPr */ ChannelFuture closeFuture(); + /** + * Returns {@code true} if and only if the I/O thread will perform the + * requested write operation immediately. Any write requests made when + * this method returns {@code false} are queued until the I/O thread is + * ready to process the queued write requests. + */ + boolean isWritable(); + /** * Returns an internal-use-only object that provides unsafe operations. */ @@ -172,7 +162,6 @@ public interface Channel extends AttributeMap, ChannelOutboundInvoker, ChannelPr * are only provided to implement the actual transport, and must be invoked from an I/O thread except for the * following methods: *

    - *
  • {@link #headContext()}
  • *
  • {@link #localAddress()}
  • *
  • {@link #remoteAddress()}
  • *
  • {@link #closeForcibly()}
  • @@ -181,11 +170,6 @@ public interface Channel extends AttributeMap, ChannelOutboundInvoker, ChannelPr *
*/ interface Unsafe { - /** - * Return the internal {@link ChannelHandlerContext} that is placed before all user handlers. - */ - ChannelHandlerContext headContext(); - /** * Return the {@link SocketAddress} to which is bound local or * {@code null} if none. @@ -250,23 +234,15 @@ public interface Channel extends AttributeMap, ChannelOutboundInvoker, ChannelPr void beginRead(); /** - * Flush out all data that was buffered in the buffer of the {@link #headContext()} and was not - * flushed out yet. After that is done the {@link ChannelFuture} will get notified + * Schedules a write operation. */ - void flush(ChannelPromise promise); + void write(MessageList msgs, ChannelPromise promise); /** * Flush out all data now. */ void flushNow(); - /** - * Send a {@link FileRegion} to the remote peer and notify the {@link ChannelPromise} once it completes - * or an error was detected. Once the {@link FileRegion} was transfered or an error was thrown it will - * automaticly call {@link FileRegion#release()}. - */ - void sendFile(FileRegion region, ChannelPromise promise); - /** * Return a special ChannelPromise which can be reused and passed to the operations in {@link Unsafe}. * It will never be notified of a success or error and so is only a placeholder for operations diff --git a/transport/src/main/java/io/netty/channel/ChannelConfig.java b/transport/src/main/java/io/netty/channel/ChannelConfig.java index ef160990f8..b9747ae210 100644 --- a/transport/src/main/java/io/netty/channel/ChannelConfig.java +++ b/transport/src/main/java/io/netty/channel/ChannelConfig.java @@ -15,7 +15,6 @@ */ package io.netty.channel; -import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBufAllocator; import io.netty.channel.socket.SocketChannelConfig; @@ -63,12 +62,6 @@ import java.util.Map; */ public interface ChannelConfig { - enum ChannelHandlerByteBufType { - HEAP, - DIRECT, - PREFER_DIRECT - } - /** * Return all set {@link ChannelOption}'s. */ @@ -158,6 +151,18 @@ public interface ChannelConfig { */ ChannelConfig setAllocator(ByteBufAllocator allocator); + /** + * Returns {@link RecvByteBufAllocator} which is used for the channel + * to allocate receive buffers. + */ + RecvByteBufAllocator getRecvByteBufAllocator(); + + /** + * Set the {@link ByteBufAllocator} which is used for the channel + * to allocate receive buffers. + */ + ChannelConfig setRecvByteBufAllocator(RecvByteBufAllocator allocator); + /** * Returns {@code true} if and only if {@link ChannelHandlerContext#read()} will be invoked automatically so that * a user application doesn't need to call it at all. The default value is {@code true}. @@ -171,21 +176,34 @@ public interface ChannelConfig { ChannelConfig setAutoRead(boolean autoRead); /** - * Returns the {@link ChannelHandlerByteBufType} which is used to determine what kind of {@link ByteBuf} will - * be created by the {@link ChannelInboundByteHandler#newInboundBuffer(ChannelHandlerContext)} and - * {@link ChannelOutboundByteHandler#newOutboundBuffer(ChannelHandlerContext)} methods. - *

- * The implementation of {@link ChannelInboundByteHandler} or {@link ChannelOutboundByteHandler} may still return - * another {@link ByteBuf} if it depends on a special type. - * - * The default is {@link ChannelHandlerByteBufType#PREFER_DIRECT}. + * Returns the high water mark of the write buffer. If the number of bytes + * queued in the write buffer exceeds this value, {@link Channel#isWritable()} + * will start to return {@code false}. */ - ChannelHandlerByteBufType getDefaultHandlerByteBufType(); + int getWriteBufferHighWaterMark(); /** - * Sets the {@link ChannelHandlerByteBufType} which is used to determine what kind of {@link ByteBuf} will - * be created by the {@link ChannelInboundByteHandler#newInboundBuffer(ChannelHandlerContext)} and - * {@link ChannelOutboundByteHandler#newOutboundBuffer(ChannelHandlerContext)} methods. + * Sets the high water mark of the write buffer. If the number of bytes + * queued in the write buffer exceeds this value, {@link Channel#isWritable()} + * will start to return {@code false}. */ - ChannelConfig setDefaultHandlerByteBufType(ChannelHandlerByteBufType type); + ChannelConfig setWriteBufferHighWaterMark(int writeBufferHighWaterMark); + + /** + * Returns the low water mark of the write buffer. Once the number of bytes + * queued in the write buffer exceeded the + * {@linkplain #setWriteBufferHighWaterMark(int) high water mark} and then + * dropped down below this value, {@link Channel#isWritable()} will start to return + * {@code true} again. + */ + int getWriteBufferLowWaterMark(); + + /** + * Sets the low water mark of the write buffer. Once the number of bytes + * queued in the write buffer exceeded the + * {@linkplain #setWriteBufferHighWaterMark(int) high water mark} and then + * dropped down below this value, {@link Channel#isWritable()} will start toreturn + * {@code true} again. + */ + ChannelConfig setWriteBufferLowWaterMark(int writeBufferLowWaterMark); } diff --git a/transport/src/main/java/io/netty/channel/ChannelDuplexHandler.java b/transport/src/main/java/io/netty/channel/ChannelDuplexHandler.java index 509c83ad6c..2a8b73bcdc 100644 --- a/transport/src/main/java/io/netty/channel/ChannelDuplexHandler.java +++ b/transport/src/main/java/io/netty/channel/ChannelDuplexHandler.java @@ -18,17 +18,17 @@ package io.netty.channel; import java.net.SocketAddress; /** - * {@link ChannelHandler} implementation which represents a combination out of a {@link ChannelStateHandler} and - * the {@link ChannelOperationHandler}. + * {@link ChannelHandler} implementation which represents a combination out of a {@link ChannelInboundHandler} and + * the {@link ChannelOutboundHandler}. * * It is a good starting point if your {@link ChannelHandler} implementation needs to intercept operations and also * state updates. */ -public abstract class ChannelDuplexHandler extends ChannelStateHandlerAdapter implements ChannelOperationHandler { +public class ChannelDuplexHandler extends ChannelInboundHandlerAdapter implements ChannelOutboundHandler { /** * Calls {@link ChannelHandlerContext#bind(SocketAddress, ChannelPromise)} to forward - * to the next {@link ChannelOperationHandler} in the {@link ChannelPipeline}. + * to the next {@link ChannelOutboundHandler} in the {@link ChannelPipeline}. * * Sub-classes may override this method to change behavior. */ @@ -40,7 +40,7 @@ public abstract class ChannelDuplexHandler extends ChannelStateHandlerAdapter im /** * Calls {@link ChannelHandlerContext#connect(SocketAddress, SocketAddress, ChannelPromise)} to forward - * to the next {@link ChannelOperationHandler} in the {@link ChannelPipeline}. + * to the next {@link ChannelOutboundHandler} in the {@link ChannelPipeline}. * * Sub-classes may override this method to change behavior. */ @@ -52,7 +52,7 @@ public abstract class ChannelDuplexHandler extends ChannelStateHandlerAdapter im /** * Calls {@link ChannelHandlerContext#disconnect(ChannelPromise)} to forward - * to the next {@link ChannelOperationHandler} in the {@link ChannelPipeline}. + * to the next {@link ChannelOutboundHandler} in the {@link ChannelPipeline}. * * Sub-classes may override this method to change behavior. */ @@ -64,41 +64,33 @@ public abstract class ChannelDuplexHandler extends ChannelStateHandlerAdapter im /** * Calls {@link ChannelHandlerContext#close(ChannelPromise)} to forward - * to the next {@link ChannelOperationHandler} in the {@link ChannelPipeline}. + * to the next {@link ChannelOutboundHandler} in the {@link ChannelPipeline}. * * Sub-classes may override this method to change behavior. */ @Override - public void close(ChannelHandlerContext ctx, ChannelPromise future) - throws Exception { + public void close(ChannelHandlerContext ctx, ChannelPromise future) throws Exception { ctx.close(future); } /** * Calls {@link ChannelHandlerContext#close(ChannelPromise)} to forward - * to the next {@link ChannelOperationHandler} in the {@link ChannelPipeline}. + * to the next {@link ChannelOutboundHandler} in the {@link ChannelPipeline}. * * Sub-classes may override this method to change behavior. */ @Override - public void deregister(ChannelHandlerContext ctx, ChannelPromise future) - throws Exception { + public void deregister(ChannelHandlerContext ctx, ChannelPromise future) throws Exception { ctx.deregister(future); } @Override - public void read(ChannelHandlerContext ctx) { + public void read(ChannelHandlerContext ctx) throws Exception { ctx.read(); } - /** - * Calls {@link ChannelHandlerContext#sendFile(FileRegion, ChannelPromise)} to forward - * to the next {@link ChannelOperationHandler} in the {@link ChannelPipeline}. - * - * Sub-classes may override this method to change behavior. - */ @Override - public void sendFile(ChannelHandlerContext ctx, FileRegion region, ChannelPromise future) throws Exception { - ctx.sendFile(region, future); + public void write(ChannelHandlerContext ctx, MessageList msgs, ChannelPromise promise) throws Exception { + ctx.write(msgs, promise); } } diff --git a/transport/src/main/java/io/netty/channel/ChannelHandler.java b/transport/src/main/java/io/netty/channel/ChannelHandler.java index ba6061fa78..3d10dc4c66 100644 --- a/transport/src/main/java/io/netty/channel/ChannelHandler.java +++ b/transport/src/main/java/io/netty/channel/ChannelHandler.java @@ -15,8 +15,6 @@ */ package io.netty.channel; -import io.netty.buffer.ByteBuf; -import io.netty.buffer.MessageBuf; import io.netty.util.Attribute; import io.netty.util.AttributeKey; @@ -40,14 +38,8 @@ import java.lang.annotation.Target; * * But the most useful for developers may be: *
    - *
  • {@link ChannelInboundByteHandlerAdapter} handles and intercepts inbound operations where the inbound message - * type is a {@link ByteBuf}.
  • - *
  • {@link ChannelInboundMessageHandlerAdapter} handles and intercepts inbound operations where the inbound message - * type is a {@link MessageBuf}.
  • - * *
  • {@link ChannelOutboundByteHandlerAdapter} handles and intercepts outbound operations where the inbound message - * type is a {@link ByteBuf}.
  • - *
  • {@link ChannelOutboundMessageHandlerAdapter} handles and intercepts outbound operations where the inbound message - * type is a {@link MessageBuf}.
  • + *
  • {@link ChannelInboundHandlerAdapter} handles and intercepts inbound operations
  • + *
  • {@link ChannelOutboundHandlerAdapter} handles and intercepts outbound operations
  • *
* * You will also find more detailed explanation from the documentation of diff --git a/transport/src/main/java/io/netty/channel/ChannelHandlerContext.java b/transport/src/main/java/io/netty/channel/ChannelHandlerContext.java index 35ebb2ac32..8935012854 100755 --- a/transport/src/main/java/io/netty/channel/ChannelHandlerContext.java +++ b/transport/src/main/java/io/netty/channel/ChannelHandlerContext.java @@ -16,9 +16,6 @@ package io.netty.channel; -import io.netty.buffer.BufType; -import io.netty.buffer.ByteBuf; -import io.netty.buffer.MessageBuf; import io.netty.util.Attribute; import io.netty.util.AttributeKey; import io.netty.util.AttributeMap; @@ -83,7 +80,7 @@ import java.nio.channels.Channels; * as how many times it is added to pipelines, regardless if it is added to the * same pipeline multiple times or added to different pipelines multiple times: *
- * public class FactorialHandler extends {@link ChannelInboundMessageHandlerAdapter}<{@link Integer}> {
+ * public class FactorialHandler extends {@link ChannelInboundHandlerAdapter}<{@link Integer}> {
  *
  *   private final {@link AttributeKey}<{@link Integer}> counter =
  *           new {@link AttributeKey}<{@link Integer}>("counter");
@@ -153,101 +150,6 @@ public interface ChannelHandlerContext
      */
     ChannelHandler handler();
 
-    /**
-     * Return {@code true} if the {@link ChannelHandlerContext} has an {@link ByteBuf} bound for inbound
-     * which can be used.
-     */
-    boolean hasInboundByteBuffer();
-
-    /**
-     * Return {@code true} if the {@link ChannelHandlerContext} has a {@link MessageBuf} bound for inbound
-     * which can be used.
-     */
-    boolean hasInboundMessageBuffer();
-
-    /**
-     * Return the bound {@link ByteBuf} for inbound data if {@link #hasInboundByteBuffer()} returned
-     * {@code true}. If {@link #hasInboundByteBuffer()} returned {@code false} it will throw a
-     * {@link UnsupportedOperationException}.
-     * 

- * This method can only be called from within the event-loop, otherwise it will throw an - * {@link IllegalStateException}. - */ - ByteBuf inboundByteBuffer(); - - /** - * Return the bound {@link MessageBuf} for inbound data if {@link #hasInboundMessageBuffer()} returned - * {@code true}. If {@link #hasInboundMessageBuffer()} returned {@code false} it will throw a - * {@link UnsupportedOperationException}. - *

- * This method can only be called from within the event-loop, otherwise it will throw an - * {@link IllegalStateException}. - */ - MessageBuf inboundMessageBuffer(); - - /** - * Return {@code true} if the {@link ChannelHandlerContext} has an {@link ByteBuf} bound for outbound - * data which can be used. - * - */ - boolean hasOutboundByteBuffer(); - - /** - * Return {@code true} if the {@link ChannelHandlerContext} has a {@link MessageBuf} bound for outbound - * which can be used. - */ - boolean hasOutboundMessageBuffer(); - - /** - * Return the bound {@link ByteBuf} for outbound data if {@link #hasOutboundByteBuffer()} returned - * {@code true}. If {@link #hasOutboundByteBuffer()} returned {@code false} it will throw - * a {@link UnsupportedOperationException}. - *

- * This method can only be called from within the event-loop, otherwise it will throw an - * {@link IllegalStateException}. - */ - ByteBuf outboundByteBuffer(); - - /** - * Return the bound {@link MessageBuf} for outbound data if {@link #hasOutboundMessageBuffer()} returned - * {@code true}. If {@link #hasOutboundMessageBuffer()} returned {@code false} it will throw a - * {@link UnsupportedOperationException}. - *

- * This method can only be called from within the event-loop, otherwise it will throw an - * {@link IllegalStateException}. - */ - MessageBuf outboundMessageBuffer(); - - /** - * Return the {@link ByteBuf} of the next {@link ChannelInboundByteHandler} in the pipeline. - */ - ByteBuf nextInboundByteBuffer(); - - /** - * Return the {@link MessageBuf} of the next {@link ChannelInboundMessageHandler} in the pipeline. - */ - MessageBuf nextInboundMessageBuffer(); - - /** - * Return the {@link ByteBuf} of the next {@link ChannelOutboundByteHandler} in the pipeline. - */ - ByteBuf nextOutboundByteBuffer(); - - /** - * Return the {@link MessageBuf} of the next {@link ChannelOutboundMessageHandler} in the pipeline. - */ - MessageBuf nextOutboundMessageBuffer(); - - /** - * Return the {@link BufType} of the next {@link ChannelInboundHandler} in the pipeline. - */ - BufType nextInboundBufferType(); - - /** - * Return the {@link BufType} of the next {@link ChannelOutboundHandler} in the pipeline. - */ - BufType nextOutboundBufferType(); - @Override ChannelHandlerContext fireChannelRegistered(); @@ -267,8 +169,14 @@ public interface ChannelHandlerContext ChannelHandlerContext fireUserEventTriggered(Object event); @Override - ChannelHandlerContext fireInboundBufferUpdated(); + ChannelHandlerContext fireMessageReceived(Object msg); + + @Override + ChannelHandlerContext fireMessageReceived(MessageList msgs); @Override ChannelHandlerContext fireChannelReadSuspended(); + + @Override + ChannelHandlerContext fireChannelWritabilityChanged(); } diff --git a/transport/src/main/java/io/netty/channel/ChannelHandlerUtil.java b/transport/src/main/java/io/netty/channel/ChannelHandlerUtil.java deleted file mode 100644 index 080bb3b4d1..0000000000 --- a/transport/src/main/java/io/netty/channel/ChannelHandlerUtil.java +++ /dev/null @@ -1,321 +0,0 @@ -/* - * Copyright 2013 The Netty Project - * - * The Netty Project licenses this file to you under the Apache License, - * version 2.0 (the "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. - */ - -package io.netty.channel; - -import io.netty.buffer.BufType; -import io.netty.buffer.BufUtil; -import io.netty.buffer.ByteBuf; -import io.netty.buffer.MessageBuf; -import io.netty.util.Signal; -import io.netty.util.internal.logging.InternalLogger; -import io.netty.util.internal.logging.InternalLoggerFactory; - -/** - * Utility methods for use within your {@link ChannelHandler} implementation. - */ -public final class ChannelHandlerUtil { - - public static final Signal ABORT = new Signal(ChannelHandlerUtil.class.getName() + ".ABORT"); - - private static final InternalLogger logger = InternalLoggerFactory.getInstance(ChannelHandlerUtil.class); - - public static void handleInboundBufferUpdated( - ChannelHandlerContext ctx, SingleInboundMessageHandler handler) throws Exception { - MessageBuf in = ctx.inboundMessageBuffer(); - if (in.isEmpty() || !handler.beginMessageReceived(ctx)) { - return; - } - - MessageBuf out = ctx.nextInboundMessageBuffer(); - int oldOutSize = out.size(); - try { - for (;;) { - Object msg = in.poll(); - if (msg == null) { - break; - } - - if (!handler.acceptInboundMessage(msg)) { - out.add(msg); - continue; - } - - @SuppressWarnings("unchecked") - T imsg = (T) msg; - try { - handler.messageReceived(ctx, imsg); - } finally { - BufUtil.release(imsg); - } - } - } catch (Signal abort) { - abort.expect(ABORT); - } finally { - if (oldOutSize != out.size()) { - ctx.fireInboundBufferUpdated(); - } - - handler.endMessageReceived(ctx); - } - } - - public static void handleFlush( - ChannelHandlerContext ctx, ChannelPromise promise, - SingleOutboundMessageHandler handler) throws Exception { - - handleFlush(ctx, promise, true, handler); - } - - public static void handleFlush( - ChannelHandlerContext ctx, ChannelPromise promise, boolean closeOnFailedFlush, - SingleOutboundMessageHandler handler) throws Exception { - - MessageBuf in = ctx.outboundMessageBuffer(); - final int inSize = in.size(); - if (inSize == 0) { - ctx.flush(promise); - return; - } - - boolean failed = false; - int processed = 0; - try { - if (!handler.beginFlush(ctx)) { - throw new IncompleteFlushException( - "beginFlush(..) rejected the flush request by returning false. " + - "none of " + inSize + " message(s) fulshed."); - } - for (;;) { - Object msg = in.poll(); - if (msg == null) { - break; - } - - if (!handler.acceptOutboundMessage(msg)) { - addToNextOutboundBuffer(ctx, msg); - processed ++; - continue; - } - - @SuppressWarnings("unchecked") - T imsg = (T) msg; - try { - handler.flush(ctx, imsg); - processed ++; - } finally { - BufUtil.release(imsg); - } - } - } catch (Throwable t) { - failed = true; - IncompleteFlushException pfe; - if (t instanceof IncompleteFlushException) { - pfe = (IncompleteFlushException) t; - } else { - String msg = processed + " out of " + inSize + " message(s) flushed"; - if (t instanceof Signal) { - Signal abort = (Signal) t; - abort.expect(ABORT); - pfe = new IncompleteFlushException("aborted: " + msg); - } else { - pfe = new IncompleteFlushException(msg, t); - } - } - fail(ctx, promise, closeOnFailedFlush, pfe); - } - - try { - handler.endFlush(ctx); - - } catch (Throwable t) { - failed = true; - fail(ctx, promise, closeOnFailedFlush, t); - } - - if (!failed) { - ctx.flush(promise); - } - } - - private static void fail( - ChannelHandlerContext ctx, ChannelPromise promise, boolean closeOnFailedFlush, Throwable cause) { - if (promise.tryFailure(cause)) { - if (closeOnFailedFlush) { - ctx.close(); - } - } else { - logger.warn("endFlush() raised a masked exception due to failed flush().", cause); - } - } - - /** - * Allocate a {@link ByteBuf} taking the {@link ChannelConfig#getDefaultHandlerByteBufType()} - * setting into account. - */ - public static ByteBuf allocate(ChannelHandlerContext ctx) { - switch(ctx.channel().config().getDefaultHandlerByteBufType()) { - case DIRECT: - return ctx.alloc().directBuffer(); - case PREFER_DIRECT: - return ctx.alloc().ioBuffer(); - case HEAP: - return ctx.alloc().heapBuffer(); - default: - throw new IllegalStateException(); - } - } - - /** - * Allocate a {@link ByteBuf} taking the {@link ChannelConfig#getDefaultHandlerByteBufType()} - * setting into account. - */ - public static ByteBuf allocate(ChannelHandlerContext ctx, int initialCapacity) { - switch(ctx.channel().config().getDefaultHandlerByteBufType()) { - case DIRECT: - return ctx.alloc().directBuffer(initialCapacity); - case PREFER_DIRECT: - return ctx.alloc().ioBuffer(initialCapacity); - case HEAP: - return ctx.alloc().heapBuffer(initialCapacity); - default: - throw new IllegalStateException(); - } - } - - /** - * Allocate a {@link ByteBuf} taking the {@link ChannelConfig#getDefaultHandlerByteBufType()} - * setting into account. - */ - public static ByteBuf allocate(ChannelHandlerContext ctx, int initialCapacity, int maxCapacity) { - switch(ctx.channel().config().getDefaultHandlerByteBufType()) { - case DIRECT: - return ctx.alloc().directBuffer(initialCapacity, maxCapacity); - case PREFER_DIRECT: - return ctx.alloc().ioBuffer(initialCapacity, maxCapacity); - case HEAP: - return ctx.alloc().heapBuffer(initialCapacity, maxCapacity); - default: - throw new IllegalStateException(); - } - } - - /** - * Add the msg to the next outbound buffer in the {@link ChannelPipeline}. This takes special care of - * msgs that are of type {@link ByteBuf}. - */ - public static boolean addToNextOutboundBuffer(ChannelHandlerContext ctx, Object msg) { - if (msg instanceof ByteBuf) { - if (ctx.nextOutboundBufferType() == BufType.BYTE) { - ctx.nextOutboundByteBuffer().writeBytes((ByteBuf) msg); - return true; - } - } - return ctx.nextOutboundMessageBuffer().add(msg); - } - - /** - * Add the msg to the next inbound buffer in the {@link ChannelPipeline}. This takes special care of - * msgs that are of type {@link ByteBuf}. - */ - public static boolean addToNextInboundBuffer(ChannelHandlerContext ctx, Object msg) { - if (msg instanceof ByteBuf) { - if (ctx.nextInboundBufferType() == BufType.BYTE) { - ctx.nextInboundByteBuffer().writeBytes((ByteBuf) msg); - return true; - } - } - return ctx.nextInboundMessageBuffer().add(msg); - } - - private ChannelHandlerUtil() { } - - public interface SingleInboundMessageHandler { - /** - * Returns {@code true} if and only if the specified message can be handled by this handler. - * - * @param msg the message - */ - boolean acceptInboundMessage(Object msg) throws Exception; - - /** - * Will get notified once {@link ChannelStateHandler#inboundBufferUpdated(ChannelHandlerContext)} was called. - * - * If this method returns {@code false} no further processing of the {@link MessageBuf} - * will be done until the next call of {@link ChannelStateHandler#inboundBufferUpdated(ChannelHandlerContext)}. - * - * This will return {@code true} by default, and may get overriden by sub-classes for - * special handling. - * - * @param ctx the {@link ChannelHandlerContext} which this {@link ChannelHandler} belongs to - */ - boolean beginMessageReceived(ChannelHandlerContext ctx) throws Exception; - - /** - * Is called once a message was received. - * - * @param ctx the {@link ChannelHandlerContext} which this {@link ChannelHandler} belongs to - * @param msg the message to handle - */ - void messageReceived(ChannelHandlerContext ctx, T msg) throws Exception; - - /** - * Is called when {@link #messageReceived(ChannelHandlerContext, Object)} returns. - * - * Super-classes may-override this for special handling. - * - * @param ctx the {@link ChannelHandlerContext} which this {@link ChannelHandler} belongs to - */ - void endMessageReceived(ChannelHandlerContext ctx) throws Exception; - } - - public interface SingleOutboundMessageHandler { - /** - * Returns {@code true} if and only if the specified message can be handled by this handler. - * - * @param msg the message - */ - boolean acceptOutboundMessage(Object msg) throws Exception; - - /** - * Will get notified once {@link ChannelOperationHandler#flush(ChannelHandlerContext, ChannelPromise)} - * was called. - * - * @param ctx the {@link ChannelHandlerContext} which this {@link ChannelHandler} belongs to - * - * @return {@code true} to accept the flush request. {@code false} to reject the flush request and - * to fail the promise associated with the flush request with {@link IncompleteFlushException}. - */ - boolean beginFlush(ChannelHandlerContext ctx) throws Exception; - - /** - * Is called once a message is being flushed. - * - * @param ctx the {@link ChannelHandlerContext} which this {@link ChannelHandler} belongs to - * @param msg the message to handle - */ - void flush(ChannelHandlerContext ctx, T msg) throws Exception; - - /** - * Is called when {@link ChannelOperationHandler#flush(ChannelHandlerContext, ChannelPromise)} returns. - * - * Super-classes may-override this for special handling. - * - * @param ctx the {@link ChannelHandlerContext} which this {@link ChannelHandler} belongs to - */ - void endFlush(ChannelHandlerContext ctx) throws Exception; - } -} diff --git a/transport/src/main/java/io/netty/channel/ChannelInboundByteHandler.java b/transport/src/main/java/io/netty/channel/ChannelInboundByteHandler.java deleted file mode 100644 index f924cd2fda..0000000000 --- a/transport/src/main/java/io/netty/channel/ChannelInboundByteHandler.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright 2012 The Netty Project - * - * The Netty Project licenses this file to you under the Apache License, - * version 2.0 (the "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. - */ -package io.netty.channel; - -import io.netty.buffer.ByteBuf; - -/** - * {@link ChannelInboundHandler} which offers a {@link ByteBuf} to store inbound data in. - * - */ -public interface ChannelInboundByteHandler extends ChannelInboundHandler { - /** - * {@inheritDoc} - *

- * An implementation should respect the {@link ChannelConfig#getDefaultHandlerByteBufType()} setting unless - * there's a good reason to ignore it. If in doubt, use {@link ChannelHandlerUtil#allocate(ChannelHandlerContext)}. - *

- */ - @Override - ByteBuf newInboundBuffer(ChannelHandlerContext ctx) throws Exception; - - /** - * Discards the read bytes of the inbound buffer and optionally trims its unused portion to reduce memory - * consumption. The most common implementation of this method will look like the following: - *
-     *     ctx.inboundByteBuffer().discardSomeReadBytes();
-     * 
- */ - void discardInboundReadBytes(ChannelHandlerContext ctx) throws Exception; -} diff --git a/transport/src/main/java/io/netty/channel/ChannelInboundByteHandlerAdapter.java b/transport/src/main/java/io/netty/channel/ChannelInboundByteHandlerAdapter.java deleted file mode 100644 index 4a50c53965..0000000000 --- a/transport/src/main/java/io/netty/channel/ChannelInboundByteHandlerAdapter.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright 2012 The Netty Project - * - * The Netty Project licenses this file to you under the Apache License, - * version 2.0 (the "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. - */ -package io.netty.channel; - -import io.netty.buffer.ByteBuf; - - -/** - * Abstract base class for {@link ChannelInboundByteHandler} which should be extended by the user to - * get notified once more data is ready to get consumed from the inbound {@link ByteBuf}. - * - * This implementation is a good starting point for most users. - */ -public abstract class ChannelInboundByteHandlerAdapter - extends ChannelStateHandlerAdapter implements ChannelInboundByteHandler { - - /** - * Create a new unpooled {@link ByteBuf} by default. Sub-classes may override this to offer a more - * optimized implementation. - */ - @Override - public ByteBuf newInboundBuffer(ChannelHandlerContext ctx) throws Exception { - return ChannelHandlerUtil.allocate(ctx); - } - - @Override - public void discardInboundReadBytes(ChannelHandlerContext ctx) throws Exception { - ctx.inboundByteBuffer().discardSomeReadBytes(); - } - - @Override - public final void inboundBufferUpdated(ChannelHandlerContext ctx) throws Exception { - inboundBufferUpdated(ctx, ctx.inboundByteBuffer()); - } - - /** - * Callback which will get notifed once the given {@link ByteBuf} received more data to read. What will be done - * with the data at this point is up to the implementation. - * Implementations may choose to read it or just let it in the buffer to read it later. - */ - protected abstract void inboundBufferUpdated(ChannelHandlerContext ctx, ByteBuf in) throws Exception; -} diff --git a/transport/src/main/java/io/netty/channel/ChannelInboundHandler.java b/transport/src/main/java/io/netty/channel/ChannelInboundHandler.java old mode 100644 new mode 100755 index 82e2f687be..a7e1817010 --- a/transport/src/main/java/io/netty/channel/ChannelInboundHandler.java +++ b/transport/src/main/java/io/netty/channel/ChannelInboundHandler.java @@ -15,19 +15,55 @@ */ package io.netty.channel; -import io.netty.buffer.Buf; - /** - * {@link ChannelStateHandler} which handles inbound data. + * {@link ChannelHandler} which adds callbacks for state changes. This allows the user + * to hook in to state changes easily. */ -interface ChannelInboundHandler extends ChannelStateHandler { +public interface ChannelInboundHandler extends ChannelHandler { + /** - * Returns a new buffer which will be used to consume inbound data for the given {@link ChannelHandlerContext}. - *

- * Please note that this method can be called from any thread repeatatively, and thus you should neither perform - * stateful operation nor keep the reference of the created buffer as a member variable. Get it always using - * {@link ChannelHandlerContext#inboundByteBuffer()} or {@link ChannelHandlerContext#inboundMessageBuffer()}. - *

+ * The {@link Channel} of the {@link ChannelHandlerContext} was registered with its {@link EventLoop} */ - Buf newInboundBuffer(ChannelHandlerContext ctx) throws Exception; + void channelRegistered(ChannelHandlerContext ctx) throws Exception; + + /** + * The {@link Channel} of the {@link ChannelHandlerContext} was unregistered from its {@link EventLoop} + */ + void channelUnregistered(ChannelHandlerContext ctx) throws Exception; + + /** + * The {@link Channel} of the {@link ChannelHandlerContext} is now active + */ + void channelActive(ChannelHandlerContext ctx) throws Exception; + + /** + * The {@link Channel} of the {@link ChannelHandlerContext} was registered is now inactive and reached its + * end of lifetime. + */ + void channelInactive(ChannelHandlerContext ctx) throws Exception; + + /** + * Invoked when a {@link ChannelHandlerContext#read()} is finished and the inbound buffer of this handler will not + * be updated until another {@link ChannelHandlerContext#read()} request is issued. + */ + void channelReadSuspended(ChannelHandlerContext ctx) throws Exception; + + /** + * The inbound buffer of the {@link ChannelHandlerContext} was updated with new data. + * This means something may be ready to get processed by the actual {@link ChannelInboundHandler} + * implementation. It's up to the implementation to consume it or keep it in the buffer + * to wait for more data and consume it later. + */ + void messageReceived(ChannelHandlerContext ctx, MessageList msgs) throws Exception; + + /** + * Gets called if an user event was triggered. + */ + void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception; + + /** + * Gets called once the writable state of a {@link Channel} changed. You can check the state with + * {@link Channel#isWritable()}. + */ + void channelWritabilityChanged(ChannelHandlerContext ctx) throws Exception; } diff --git a/transport/src/main/java/io/netty/channel/ChannelStateHandlerAdapter.java b/transport/src/main/java/io/netty/channel/ChannelInboundHandlerAdapter.java similarity index 63% rename from transport/src/main/java/io/netty/channel/ChannelStateHandlerAdapter.java rename to transport/src/main/java/io/netty/channel/ChannelInboundHandlerAdapter.java index 8a67804497..edd0856f6e 100644 --- a/transport/src/main/java/io/netty/channel/ChannelStateHandlerAdapter.java +++ b/transport/src/main/java/io/netty/channel/ChannelInboundHandlerAdapter.java @@ -17,17 +17,17 @@ package io.netty.channel; /** - * Abstract base class for {@link ChannelStateHandler} implementations which provide + * Abstract base class for {@link ChannelInboundHandler} implementations which provide * implementations of all of their methods. * * This implementation just forward the operation to the next {@link ChannelHandler} in the * {@link ChannelPipeline}. Sub-classes may override a method implementation to change this. */ -public abstract class ChannelStateHandlerAdapter extends ChannelHandlerAdapter implements ChannelStateHandler { +public class ChannelInboundHandlerAdapter extends ChannelHandlerAdapter implements ChannelInboundHandler { /** * Calls {@link ChannelHandlerContext#fireChannelRegistered()} to forward - * to the next {@link ChannelStateHandler} in the {@link ChannelPipeline}. + * to the next {@link ChannelInboundHandler} in the {@link ChannelPipeline}. * * Sub-classes may override this method to change behavior. */ @@ -38,7 +38,7 @@ public abstract class ChannelStateHandlerAdapter extends ChannelHandlerAdapter i /** * Calls {@link ChannelHandlerContext#fireChannelUnregistered()} to forward - * to the next {@link ChannelStateHandler} in the {@link ChannelPipeline}. + * to the next {@link ChannelInboundHandler} in the {@link ChannelPipeline}. * * Sub-classes may override this method to change behavior. */ @@ -49,7 +49,7 @@ public abstract class ChannelStateHandlerAdapter extends ChannelHandlerAdapter i /** * Calls {@link ChannelHandlerContext#fireChannelActive()} to forward - * to the next {@link ChannelStateHandler} in the {@link ChannelPipeline}. + * to the next {@link ChannelInboundHandler} in the {@link ChannelPipeline}. * * Sub-classes may override this method to change behavior. */ @@ -60,7 +60,7 @@ public abstract class ChannelStateHandlerAdapter extends ChannelHandlerAdapter i /** * Calls {@link ChannelHandlerContext#fireChannelInactive()} to forward - * to the next {@link ChannelStateHandler} in the {@link ChannelPipeline}. + * to the next {@link ChannelInboundHandler} in the {@link ChannelPipeline}. * * Sub-classes may override this method to change behavior. */ @@ -70,7 +70,7 @@ public abstract class ChannelStateHandlerAdapter extends ChannelHandlerAdapter i } /** * Calls {@link ChannelHandlerContext#fireChannelReadSuspended()} to forward - * to the next {@link ChannelHandler} in the {@link ChannelPipeline}. + * to the next {@link ChannelInboundHandler} in the {@link ChannelPipeline}. * * Sub-classes may override this method to change behavior. */ @@ -80,14 +80,35 @@ public abstract class ChannelStateHandlerAdapter extends ChannelHandlerAdapter i } /** - * Calls {@link ChannelHandlerContext#fireUserEventTriggered(Object)} to forward - * to the next {@link ChannelHandler} in the {@link ChannelPipeline}. + * Calls {@link ChannelHandlerContext#fireMessageReceived(MessageList)} to forward + * to the next {@link ChannelInboundHandler} in the {@link ChannelPipeline}. * * Sub-classes may override this method to change behavior. */ @Override - public void userEventTriggered(ChannelHandlerContext ctx, Object evt) - throws Exception { + public void messageReceived(ChannelHandlerContext ctx, MessageList msgs) throws Exception { + ctx.fireMessageReceived(msgs); + } + + /** + * Calls {@link ChannelHandlerContext#fireUserEventTriggered(Object)} to forward + * to the next {@link ChannelInboundHandler} in the {@link ChannelPipeline}. + * + * Sub-classes may override this method to change behavior. + */ + @Override + public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception { ctx.fireUserEventTriggered(evt); } + + /** + * Calls {@link ChannelHandlerContext#fireChannelWritabilityChanged()} to forward + * to the next {@link ChannelInboundHandler} in the {@link ChannelPipeline}. + * + * Sub-classes may override this method to change behavior. + */ + @Override + public void channelWritabilityChanged(ChannelHandlerContext ctx) throws Exception { + ctx.fireChannelWritabilityChanged(); + } } diff --git a/transport/src/main/java/io/netty/channel/ChannelInboundInvoker.java b/transport/src/main/java/io/netty/channel/ChannelInboundInvoker.java index 2fb8118d93..ac12c17505 100644 --- a/transport/src/main/java/io/netty/channel/ChannelInboundInvoker.java +++ b/transport/src/main/java/io/netty/channel/ChannelInboundInvoker.java @@ -24,8 +24,8 @@ interface ChannelInboundInvoker { /** * A {@link Channel} was registered to its {@link EventLoop}. * - * This will result in having the {@link ChannelStateHandler#channelRegistered(ChannelHandlerContext)} method - * called of the next {@link ChannelStateHandler} contained in the {@link ChannelPipeline} of the + * This will result in having the {@link ChannelInboundHandler#channelRegistered(ChannelHandlerContext)} method + * called of the next {@link ChannelInboundHandler} contained in the {@link ChannelPipeline} of the * {@link Channel}. */ ChannelInboundInvoker fireChannelRegistered(); @@ -33,8 +33,8 @@ interface ChannelInboundInvoker { /** * A {@link Channel} was unregistered from its {@link EventLoop}. * - * This will result in having the {@link ChannelStateHandler#channelUnregistered(ChannelHandlerContext)} method - * called of the next {@link ChannelStateHandler} contained in the {@link ChannelPipeline} of the + * This will result in having the {@link ChannelInboundHandler#channelUnregistered(ChannelHandlerContext)} method + * called of the next {@link ChannelInboundHandler} contained in the {@link ChannelPipeline} of the * {@link Channel}. */ ChannelInboundInvoker fireChannelUnregistered(); @@ -42,8 +42,8 @@ interface ChannelInboundInvoker { /** * A {@link Channel} is active now, which means it is connected. * - * This will result in having the {@link ChannelStateHandler#channelActive(ChannelHandlerContext)} method - * called of the next {@link ChannelStateHandler} contained in the {@link ChannelPipeline} of the + * This will result in having the {@link ChannelInboundHandler#channelActive(ChannelHandlerContext)} method + * called of the next {@link ChannelInboundHandler} contained in the {@link ChannelPipeline} of the * {@link Channel}. */ ChannelInboundInvoker fireChannelActive(); @@ -51,8 +51,8 @@ interface ChannelInboundInvoker { /** * A {@link Channel} is inactive now, which means it is closed. * - * This will result in having the {@link ChannelStateHandler#channelInactive(ChannelHandlerContext)} method - * called of the next {@link ChannelStateHandler} contained in the {@link ChannelPipeline} of the + * This will result in having the {@link ChannelInboundHandler#channelInactive(ChannelHandlerContext)} method + * called of the next {@link ChannelInboundHandler} contained in the {@link ChannelPipeline} of the * {@link Channel}. */ ChannelInboundInvoker fireChannelInactive(); @@ -60,8 +60,8 @@ interface ChannelInboundInvoker { /** * A {@link Channel} received an {@link Throwable} in one of its inbound operations. * - * This will result in having the {@link ChannelStateHandler#exceptionCaught(ChannelHandlerContext, Throwable)} - * method called of the next {@link ChannelStateHandler} contained in the {@link ChannelPipeline} of the + * This will result in having the {@link ChannelInboundHandler#exceptionCaught(ChannelHandlerContext, Throwable)} + * method called of the next {@link ChannelInboundHandler} contained in the {@link ChannelPipeline} of the * {@link Channel}. */ ChannelInboundInvoker fireExceptionCaught(Throwable cause); @@ -69,8 +69,8 @@ interface ChannelInboundInvoker { /** * A {@link Channel} received an user defined event. * - * This will result in having the {@link ChannelStateHandler#userEventTriggered(ChannelHandlerContext, Object)} - * method called of the next {@link ChannelStateHandler} contained in the {@link ChannelPipeline} of the + * This will result in having the {@link ChannelInboundHandler#userEventTriggered(ChannelHandlerContext, Object)} + * method called of the next {@link ChannelInboundHandler} contained in the {@link ChannelPipeline} of the * {@link Channel}. */ ChannelInboundInvoker fireUserEventTriggered(Object event); @@ -78,15 +78,22 @@ interface ChannelInboundInvoker { /** * A {@link Channel} received bytes which are now ready to read from its inbound buffer. * - * This will result in having the {@link ChannelStateHandler#inboundBufferUpdated(ChannelHandlerContext)} - * method called of the next {@link ChannelStateHandler} contained in the {@link ChannelPipeline} of the + * This will result in having the {@link ChannelInboundHandler#messageReceived(ChannelHandlerContext, MessageList)} + * method called of the next {@link ChannelInboundHandler} contained in the {@link ChannelPipeline} of the * {@link Channel}. */ - ChannelInboundInvoker fireInboundBufferUpdated(); + ChannelInboundInvoker fireMessageReceived(Object msg); + ChannelInboundInvoker fireMessageReceived(MessageList msgs); /** - * Triggers an {@link ChannelStateHandler#channelReadSuspended(ChannelHandlerContext) channelReadSuspended} - * event to the next {@link ChannelStateHandler} in the {@link ChannelPipeline}. + * Triggers an {@link ChannelInboundHandler#channelReadSuspended(ChannelHandlerContext) channelReadSuspended} + * event to the next {@link ChannelInboundHandler} in the {@link ChannelPipeline}. */ ChannelInboundInvoker fireChannelReadSuspended(); + + /** + * Triggers an {@link ChannelInboundHandler#channelWritabilityChanged(ChannelHandlerContext)} + * event to the next {@link ChannelInboundHandler} in the {@link ChannelPipeline}. + */ + ChannelInboundInvoker fireChannelWritabilityChanged(); } diff --git a/transport/src/main/java/io/netty/channel/ChannelInboundMessageHandler.java b/transport/src/main/java/io/netty/channel/ChannelInboundMessageHandler.java deleted file mode 100644 index d3e72ca069..0000000000 --- a/transport/src/main/java/io/netty/channel/ChannelInboundMessageHandler.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright 2012 The Netty Project - * - * The Netty Project licenses this file to you under the Apache License, - * version 2.0 (the "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. - */ -package io.netty.channel; - -import io.netty.buffer.ByteBuf; -import io.netty.buffer.MessageBuf; - -/** - * Special {@link ChannelInboundHandler} which store the inbound data in a {@link MessageBuf} for futher processing. - * - * If your {@link ChannelOutboundMessageHandler} handles messages of type {@link ByteBuf} or {@link Object} - * and you want to add a {@link ByteBuf} to the next buffer in the {@link ChannelPipeline} use - * {@link ChannelHandlerUtil#addToNextInboundBuffer(ChannelHandlerContext, Object)}. - */ -public interface ChannelInboundMessageHandler extends ChannelInboundHandler { - @Override - MessageBuf newInboundBuffer(ChannelHandlerContext ctx) throws Exception; -} diff --git a/transport/src/main/java/io/netty/channel/ChannelInboundMessageHandlerAdapter.java b/transport/src/main/java/io/netty/channel/ChannelInboundMessageHandlerAdapter.java deleted file mode 100644 index 79a5927be6..0000000000 --- a/transport/src/main/java/io/netty/channel/ChannelInboundMessageHandlerAdapter.java +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Copyright 2012 The Netty Project - * - * The Netty Project licenses this file to you under the Apache License, - * version 2.0 (the "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. - */ -package io.netty.channel; - -import io.netty.buffer.ByteBuf; -import io.netty.buffer.MessageBuf; -import io.netty.buffer.Unpooled; -import io.netty.channel.ChannelHandlerUtil.SingleInboundMessageHandler; -import io.netty.util.Signal; -import io.netty.util.internal.TypeParameterMatcher; - -/** - * {@link ChannelHandler} which handles inbound messages of a specific type. - * - *
- *     public class StringHandler extends
- *             {@link ChannelInboundMessageHandlerAdapter}<{@link String}> {
- *
- *         {@code @Override}
- *         public void messageReceived({@link ChannelHandlerContext} ctx, {@link String} message)
- *                 throws {@link Exception} {
- *             // Do something with the String
- *             ...
- *             ...
- *         }
- *     }
- * 
- * - * If your {@link ChannelInboundMessageHandlerAdapter} handles messages of type {@link ByteBuf} or {@link Object} - * and you want to add a {@link ByteBuf} to the next buffer in the {@link ChannelPipeline} use - * {@link ChannelHandlerUtil#addToNextInboundBuffer(ChannelHandlerContext, Object)}. - * - *

- * One limitation to keep in mind is that it is not possible to detect the handled message type of you specify - * {@code I} while instance your class. Because of this Netty does not allow to do so and will throw an Exception - * if you try. For this cases you should handle the type detection by your self by override the - * {@link #acceptInboundMessage(Object)} method and use {@link Object} as type parameter. - * - *

- *    public class GenericHandler<I> extends
- *             {@link ChannelInboundMessageHandlerAdapter}<{@link Object}> {
- *
- *         {@code @Override}
- *         public void messageReceived({@link ChannelHandlerContext} ctx, {@link Object} message)
- *                 throws {@link Exception} {
- *             I msg = (I) message;
- *             // Do something with the msg
- *             ...
- *             ...
- *         }
- *
- *         {@code @Override}
- *         public boolean acceptInboundMessage(Object msg) throws Exception {
- *             // Add your check here
- *         }
- *     }
- * 
- * - * @param The type of the messages to handle - */ -public abstract class ChannelInboundMessageHandlerAdapter - extends ChannelStateHandlerAdapter - implements ChannelInboundMessageHandler, SingleInboundMessageHandler { - - /** - * Thrown by {@link #messageReceived(ChannelHandlerContext, Object)} to abort message processing. - */ - protected static final Signal ABORT = ChannelHandlerUtil.ABORT; - - private final TypeParameterMatcher msgMatcher; - - protected ChannelInboundMessageHandlerAdapter() { - msgMatcher = TypeParameterMatcher.find(this, ChannelInboundMessageHandlerAdapter.class, "I"); - } - - protected ChannelInboundMessageHandlerAdapter(Class inboundMessageType) { - msgMatcher = TypeParameterMatcher.get(inboundMessageType); - } - - @Override - public MessageBuf newInboundBuffer(ChannelHandlerContext ctx) throws Exception { - return Unpooled.messageBuffer(); - } - - @Override - public final void inboundBufferUpdated(ChannelHandlerContext ctx) throws Exception { - ChannelHandlerUtil.handleInboundBufferUpdated(ctx, this); - } - - @Override - public boolean acceptInboundMessage(Object msg) throws Exception { - return msgMatcher.match(msg); - } - - @Override - public boolean beginMessageReceived(ChannelHandlerContext ctx) throws Exception { - return true; - } - - @Override - public void endMessageReceived(ChannelHandlerContext ctx) throws Exception { - // NOOP - } -} diff --git a/transport/src/main/java/io/netty/channel/ChannelInitializer.java b/transport/src/main/java/io/netty/channel/ChannelInitializer.java index a183b01cc0..d03cc2e585 100644 --- a/transport/src/main/java/io/netty/channel/ChannelInitializer.java +++ b/transport/src/main/java/io/netty/channel/ChannelInitializer.java @@ -22,7 +22,7 @@ import io.netty.util.internal.logging.InternalLogger; import io.netty.util.internal.logging.InternalLoggerFactory; /** - * A special {@link ChannelStateHandler} which offers an easy way to initialize a {@link Channel} once it was + * A special {@link ChannelInboundHandler} which offers an easy way to initialize a {@link Channel} once it was * registered to its {@link EventLoop}. * * Implementations are most often used in the context of {@link Bootstrap#handler(ChannelHandler)} , @@ -47,7 +47,7 @@ import io.netty.util.internal.logging.InternalLoggerFactory; * @param A sub-type of {@link Channel} */ @Sharable -public abstract class ChannelInitializer extends ChannelStateHandlerAdapter { +public abstract class ChannelInitializer extends ChannelInboundHandlerAdapter { private static final InternalLogger logger = InternalLoggerFactory.getInstance(ChannelInitializer.class); @@ -83,9 +83,4 @@ public abstract class ChannelInitializer extends ChannelState } } } - - @Override - public void inboundBufferUpdated(ChannelHandlerContext ctx) throws Exception { - ctx.fireInboundBufferUpdated(); - } } diff --git a/transport/src/main/java/io/netty/channel/ChannelMetadata.java b/transport/src/main/java/io/netty/channel/ChannelMetadata.java index c5d2a2cd51..628ad43fdd 100644 --- a/transport/src/main/java/io/netty/channel/ChannelMetadata.java +++ b/transport/src/main/java/io/netty/channel/ChannelMetadata.java @@ -15,8 +15,6 @@ */ package io.netty.channel; -import io.netty.buffer.BufType; - import java.net.SocketAddress; /** @@ -24,33 +22,19 @@ import java.net.SocketAddress; */ public final class ChannelMetadata { - private final BufType bufferType; private final boolean hasDisconnect; /** * Create a new instance * - * @param bufferType the {@link BufType} which will be used by the {@link Channel}. * @param hasDisconnect {@code true} if and only if the channel has the {@code disconnect()} operation * that allows a user to disconnect and then call {@link Channel#connect(SocketAddress)} * again, such as UDP/IP. */ - public ChannelMetadata(BufType bufferType, boolean hasDisconnect) { - if (bufferType == null) { - throw new NullPointerException("bufferType"); - } - - this.bufferType = bufferType; + public ChannelMetadata(boolean hasDisconnect) { this.hasDisconnect = hasDisconnect; } - /** - * Returns the {@link BufType} which will be used by the {@link Channel}. - */ - public BufType bufferType() { - return bufferType; - } - /** * Returns {@code true} if and only if the channel has the {@code disconnect()} operation * that allows a user to disconnect and then call {@link Channel#connect(SocketAddress)} again, diff --git a/transport/src/main/java/io/netty/channel/ChannelOperationHandler.java b/transport/src/main/java/io/netty/channel/ChannelOperationHandler.java deleted file mode 100644 index 3ff70f5ce3..0000000000 --- a/transport/src/main/java/io/netty/channel/ChannelOperationHandler.java +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Copyright 2012 The Netty Project - * - * The Netty Project licenses this file to you under the Apache License, - * version 2.0 (the "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. - */ -package io.netty.channel; - -import java.net.SocketAddress; - -/** - * {@link ChannelHandler} which will get notified for IO-outbound-operations. - */ -public interface ChannelOperationHandler extends ChannelHandler { - /** - * Called once a bind operation is made. - * - * @param ctx the {@link ChannelHandlerContext} for which the bind operation is made - * @param localAddress the {@link SocketAddress} to which it should bound - * @param promise the {@link ChannelPromise} to notify once the operation completes - * @throws Exception thrown if an error accour - */ - void bind(ChannelHandlerContext ctx, SocketAddress localAddress, ChannelPromise promise) throws Exception; - - /** - * Called once a connect operation is made. - * - * @param ctx the {@link ChannelHandlerContext} for which the connect operation is made - * @param remoteAddress the {@link SocketAddress} to which it should connect - * @param localAddress the {@link SocketAddress} which is used as source on connect - * @param promise the {@link ChannelPromise} to notify once the operation completes - * @throws Exception thrown if an error accour - */ - void connect( - ChannelHandlerContext ctx, SocketAddress remoteAddress, - SocketAddress localAddress, ChannelPromise promise) throws Exception; - - /** - * Called once a disconnect operation is made. - * - * @param ctx the {@link ChannelHandlerContext} for which the disconnect operation is made - * @param promise the {@link ChannelPromise} to notify once the operation completes - * @throws Exception thrown if an error accour - */ - void disconnect(ChannelHandlerContext ctx, ChannelPromise promise) throws Exception; - - /** - * Called once a close operation is made. - * - * @param ctx the {@link ChannelHandlerContext} for which the close operation is made - * @param promise the {@link ChannelPromise} to notify once the operation completes - * @throws Exception thrown if an error accour - */ - void close(ChannelHandlerContext ctx, ChannelPromise promise) throws Exception; - - /** - * Called once a deregister operation is made from the current registered {@link EventLoop}. - * - * @param ctx the {@link ChannelHandlerContext} for which the close operation is made - * @param promise the {@link ChannelPromise} to notify once the operation completes - * @throws Exception thrown if an error accour - */ - void deregister(ChannelHandlerContext ctx, ChannelPromise promise) throws Exception; - - /** - * Intercepts {@link ChannelHandlerContext#read()}. - */ - void read(ChannelHandlerContext ctx); - - /** - * Called once a flush operation is made and so the outbound data should be written. - * - * @param ctx the {@link ChannelHandlerContext} for which the flush operation is made - * @param promise the {@link ChannelPromise} to notify once the operation completes - * @throws Exception thrown if an error accour - */ - void flush(ChannelHandlerContext ctx, ChannelPromise promise) throws Exception; - - /** - * Called once a sendFile operation is made and so the {@link FileRegion} should be transfered. - * - * @param ctx the {@link ChannelHandlerContext} for which the flush operation is made - * @param region the {@link FileRegion} to transfer - * @param promise the {@link ChannelPromise} to notify once the operation completes - * @throws Exception thrown if an error accour - */ - void sendFile(ChannelHandlerContext ctx, FileRegion region, ChannelPromise promise) throws Exception; - -} diff --git a/transport/src/main/java/io/netty/channel/ChannelOption.java b/transport/src/main/java/io/netty/channel/ChannelOption.java index 6ad40e1dd6..f7231ee844 100644 --- a/transport/src/main/java/io/netty/channel/ChannelOption.java +++ b/transport/src/main/java/io/netty/channel/ChannelOption.java @@ -35,17 +35,25 @@ public class ChannelOption extends UniqueName { private static final ConcurrentMap names = PlatformDependent.newConcurrentHashMap(); - public static final ChannelOption ALLOCATOR = new ChannelOption("ALLOCATOR"); + public static final ChannelOption ALLOCATOR = + new ChannelOption("ALLOCATOR"); + public static final ChannelOption RCVBUF_ALLOCATOR = + new ChannelOption("RCVBUF_ALLOCATOR"); + public static final ChannelOption CONNECT_TIMEOUT_MILLIS = new ChannelOption("CONNECT_TIMEOUT_MILLIS"); public static final ChannelOption WRITE_SPIN_COUNT = new ChannelOption("WRITE_SPIN_COUNT"); + public static final ChannelOption WRITE_BUFFER_HIGH_WATER_MARK = + new ChannelOption("WRITE_BUFFER_HIGH_WATER_MARK"); + public static final ChannelOption WRITE_BUFFER_LOW_WATER_MARK = + new ChannelOption("WRITE_BUFFER_LOW_WATER_MARK"); + public static final ChannelOption ALLOW_HALF_CLOSURE = new ChannelOption("ALLOW_HALF_CLOSURE"); public static final ChannelOption AUTO_READ = new ChannelOption("AUTO_READ"); - public static final ChannelOption DEFAULT_HANDLER_BYTEBUF_TYPE = - new ChannelOption("DEFAULT_HANDLER_BYTEBUF_TYPE"); + public static final ChannelOption SO_BROADCAST = new ChannelOption("SO_BROADCAST"); public static final ChannelOption SO_KEEPALIVE = @@ -74,9 +82,6 @@ public class ChannelOption extends UniqueName { public static final ChannelOption IP_MULTICAST_LOOP_DISABLED = new ChannelOption("IP_MULTICAST_LOOP_DISABLED"); - public static final ChannelOption UDP_RECEIVE_PACKET_SIZE = - new ChannelOption("UDP_RECEIVE_PACKET_SIZE"); - public static final ChannelOption TCP_NODELAY = new ChannelOption("TCP_NODELAY"); diff --git a/transport/src/main/java/io/netty/channel/ChannelOutboundBuffer.java b/transport/src/main/java/io/netty/channel/ChannelOutboundBuffer.java new file mode 100644 index 0000000000..a6457a1717 --- /dev/null +++ b/transport/src/main/java/io/netty/channel/ChannelOutboundBuffer.java @@ -0,0 +1,238 @@ +/* + * Copyright 2013 The Netty Project + * + * The Netty Project licenses this file to you under the Apache License, + * version 2.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +/* + * Written by Josh Bloch of Google Inc. and released to the public domain, + * as explained at http://creativecommons.org/publicdomain/zero/1.0/. + */ +package io.netty.channel; + +import io.netty.buffer.ByteBufUtil; +import io.netty.util.internal.logging.InternalLogger; +import io.netty.util.internal.logging.InternalLoggerFactory; + +import java.util.concurrent.atomic.AtomicIntegerFieldUpdater; + +final class ChannelOutboundBuffer { + + private static final InternalLogger logger = InternalLoggerFactory.getInstance(ChannelOutboundBuffer.class); + + private static final int MIN_INITIAL_CAPACITY = 8; + + ChannelPromise currentPromise; + MessageList currentMessages; + int currentMessageIndex; + private int currentMessageListSize; + + private ChannelPromise[] promises; + private MessageList[] messages; + + private int head; + private int tail; + private final AbstractChannel channel; + + private int pendingOutboundBytes; + + private static final AtomicIntegerFieldUpdater WRITABLE_UPDATER = + AtomicIntegerFieldUpdater.newUpdater(ChannelOutboundBuffer.class, "writable"); + + @SuppressWarnings("unused") + private volatile int writable = 1; + + ChannelOutboundBuffer(AbstractChannel channel) { + this(channel, MIN_INITIAL_CAPACITY << 1); + } + + @SuppressWarnings("unchecked") + ChannelOutboundBuffer(AbstractChannel channel, int initialCapacity) { + if (initialCapacity < 0) { + throw new IllegalArgumentException("initialCapacity: " + initialCapacity + " (expected: >= 0)"); + } + // Find the best power of two to hold elements. + // Tests "<=" because arrays aren't kept full. + if (initialCapacity >= MIN_INITIAL_CAPACITY) { + initialCapacity |= initialCapacity >>> 1; + initialCapacity |= initialCapacity >>> 2; + initialCapacity |= initialCapacity >>> 4; + initialCapacity |= initialCapacity >>> 8; + initialCapacity |= initialCapacity >>> 16; + initialCapacity ++; + + if (initialCapacity < 0) { // Too many elements, must back off + initialCapacity >>>= 1; // Good luck allocating 2 ^ 30 elements + } + } else { + initialCapacity = MIN_INITIAL_CAPACITY; + } + + promises = new ChannelPromise[initialCapacity]; + messages = new MessageList[initialCapacity]; + this.channel = channel; + } + + @SuppressWarnings("unchecked") + void add(MessageList msgs, ChannelPromise promise) { + int tail = this.tail; + promises[tail] = promise; + messages[tail] = (MessageList) msgs; + + if ((this.tail = tail + 1 & promises.length - 1) == head) { + doubleCapacity(); + } + + incrementPendingOutboundBytes(messageListSize(msgs)); + } + + private void incrementPendingOutboundBytes(int size) { + if (size == 0) { + return; + } + + int newWriteBufferSize = pendingOutboundBytes += size; + int highWaterMark = channel.config().getWriteBufferHighWaterMark(); + + if (newWriteBufferSize > highWaterMark) { + if (WRITABLE_UPDATER.compareAndSet(this, 1, 0)) { + channel.pipeline().fireChannelWritabilityChanged(); + } + } + } + + private void decrementPendingOutboundBytes(int size) { + if (size == 0) { + return; + } + + int newWriteBufferSize = pendingOutboundBytes -= size; + int lowWaterMark = channel.config().getWriteBufferLowWaterMark(); + + if (newWriteBufferSize == 0 || newWriteBufferSize < lowWaterMark) { + + if (WRITABLE_UPDATER.compareAndSet(this, 0, 1)) { + channel.pipeline().fireChannelWritabilityChanged(); + } + } + } + + private void doubleCapacity() { + assert head == tail; + + int p = head; + int n = promises.length; + int r = n - p; // number of elements to the right of p + int newCapacity = n << 1; + if (newCapacity < 0) { + throw new IllegalStateException("Sorry, deque too big"); + } + + ChannelPromise[] a1 = new ChannelPromise[newCapacity]; + System.arraycopy(promises, p, a1, 0, r); + System.arraycopy(promises, 0, a1, r, p); + promises = a1; + + @SuppressWarnings("unchecked") + MessageList[] a2 = new MessageList[newCapacity]; + System.arraycopy(messages, p, a2, 0, r); + System.arraycopy(messages, 0, a2, r, p); + messages = a2; + + head = 0; + tail = n; + } + + boolean next() { + decrementPendingOutboundBytes(currentMessageListSize); + + int h = head; + + ChannelPromise e = promises[h]; // Element is null if deque empty + if (e == null) { + currentMessageListSize = 0; + currentPromise = null; + currentMessages = null; + return false; + } + + currentPromise = e; + currentMessages = messages[h]; + currentMessageIndex = 0; + currentMessageListSize = messageListSize(currentMessages); + + promises[h] = null; + messages[h] = null; + + head = h + 1 & promises.length - 1; + return true; + } + + private int messageListSize(MessageList messages) { + int size = 0; + for (int i = 0; i < messages.size(); i++) { + size += channel.calculateMessageSize(messages.get(i)); + } + return size; + } + + boolean getWritable() { + return WRITABLE_UPDATER.get(this) == 1; + } + + int size() { + return tail - head & promises.length - 1; + } + + boolean isEmpty() { + return head == tail; + } + + void clear() { + int head = this.head; + int tail = this.tail; + if (head != tail) { + this.head = this.tail = 0; + final int mask = promises.length - 1; + int i = head; + do { + promises[i] = null; + messages[i] = null; + i = i + 1 & mask; + } while (i != tail); + } + } + + void fail(Throwable cause) { + if (currentPromise == null) { + if (!next()) { + return; + } + } + + do { + if (!currentPromise.tryFailure(cause)) { + logger.warn("Promise done already:", cause); + } + + // Release all failed messages. + try { + for (int i = currentMessageIndex; i < currentMessages.size(); i++) { + Object msg = currentMessages.get(i); + ByteBufUtil.release(msg); + } + } finally { + currentMessages.recycle(); + } + } while(next()); + } +} diff --git a/transport/src/main/java/io/netty/channel/ChannelOutboundByteHandler.java b/transport/src/main/java/io/netty/channel/ChannelOutboundByteHandler.java deleted file mode 100644 index 82b042fe0d..0000000000 --- a/transport/src/main/java/io/netty/channel/ChannelOutboundByteHandler.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright 2012 The Netty Project - * - * The Netty Project licenses this file to you under the Apache License, - * version 2.0 (the "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. - */ -package io.netty.channel; - -import io.netty.buffer.ByteBuf; - -/** - * {@link ChannelOutboundHandler} which operates on bytes which are hold in a {@link ByteBuf}. - */ -public interface ChannelOutboundByteHandler extends ChannelOutboundHandler { - /** - * {@inheritDoc} - *

- * An implementation should respect the {@link ChannelConfig#getDefaultHandlerByteBufType()} setting unless - * there's a good reason to ignore it. If in doubt, use {@link ChannelHandlerUtil#allocate(ChannelHandlerContext)}. - *

- */ - @Override - ByteBuf newOutboundBuffer(ChannelHandlerContext ctx) throws Exception; - - /** - * Discards the read bytes of the outbound buffer and optionally trims its unused portion to reduce memory - * consumption. The most common implementation of this method will look like the following: - *
-     *     ctx.outboundByteBuffer().discardSomeReadBytes();
-     * 
- */ - void discardOutboundReadBytes(ChannelHandlerContext ctx) throws Exception; -} diff --git a/transport/src/main/java/io/netty/channel/ChannelOutboundByteHandlerAdapter.java b/transport/src/main/java/io/netty/channel/ChannelOutboundByteHandlerAdapter.java deleted file mode 100644 index d5036d6e20..0000000000 --- a/transport/src/main/java/io/netty/channel/ChannelOutboundByteHandlerAdapter.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright 2012 The Netty Project - * - * The Netty Project licenses this file to you under the Apache License, - * version 2.0 (the "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. - */ -package io.netty.channel; - -import io.netty.buffer.ByteBuf; - -/** - * Abstract base class which handles outgoing bytes. - */ -public abstract class ChannelOutboundByteHandlerAdapter - extends ChannelOperationHandlerAdapter implements ChannelOutboundByteHandler { - @Override - public ByteBuf newOutboundBuffer(ChannelHandlerContext ctx) throws Exception { - return ChannelHandlerUtil.allocate(ctx); - } - - @Override - public void discardOutboundReadBytes(ChannelHandlerContext ctx) throws Exception { - ctx.outboundByteBuffer().discardSomeReadBytes(); - } - - /** - * This method merely delegates the flush request to {@link #flush(ChannelHandlerContext, ByteBuf, ChannelPromise)}. - */ - @Override - public final void flush(ChannelHandlerContext ctx, ChannelPromise promise) throws Exception { - flush(ctx, ctx.outboundByteBuffer(), promise); - } - - /** - * Invoked when a flush request has been issued. - * - * @param ctx the current context - * @param in this handler's outbound buffer - * @param promise the promise associate with the current flush request - */ - protected abstract void flush(ChannelHandlerContext ctx, ByteBuf in, ChannelPromise promise) throws Exception; -} diff --git a/transport/src/main/java/io/netty/channel/ChannelOutboundHandler.java b/transport/src/main/java/io/netty/channel/ChannelOutboundHandler.java index 1bcf3325b7..c55f9d5f5d 100644 --- a/transport/src/main/java/io/netty/channel/ChannelOutboundHandler.java +++ b/transport/src/main/java/io/netty/channel/ChannelOutboundHandler.java @@ -15,19 +15,74 @@ */ package io.netty.channel; -import io.netty.buffer.Buf; +import java.net.SocketAddress; /** - * {@link ChannelOperationHandler} which handles outbound data. + * {@link ChannelHandler} which will get notified for IO-outbound-operations. */ -interface ChannelOutboundHandler extends ChannelOperationHandler { +public interface ChannelOutboundHandler extends ChannelHandler { /** - * Returns a new buffer which will be used to transfer outbound data for the given {@link ChannelHandlerContext}. - *

- * Please note that this method can be called from any thread repeatatively, and thus you should neither perform - * stateful operation nor keep the reference of the created buffer as a member variable. Get it always using - * {@link ChannelHandlerContext#outboundByteBuffer()} or {@link ChannelHandlerContext#outboundMessageBuffer()}. - *

+ * Called once a bind operation is made. + * + * @param ctx the {@link ChannelHandlerContext} for which the bind operation is made + * @param localAddress the {@link SocketAddress} to which it should bound + * @param promise the {@link ChannelPromise} to notify once the operation completes + * @throws Exception thrown if an error accour */ - Buf newOutboundBuffer(ChannelHandlerContext ctx) throws Exception; + void bind(ChannelHandlerContext ctx, SocketAddress localAddress, ChannelPromise promise) throws Exception; + + /** + * Called once a connect operation is made. + * + * @param ctx the {@link ChannelHandlerContext} for which the connect operation is made + * @param remoteAddress the {@link SocketAddress} to which it should connect + * @param localAddress the {@link SocketAddress} which is used as source on connect + * @param promise the {@link ChannelPromise} to notify once the operation completes + * @throws Exception thrown if an error accour + */ + void connect( + ChannelHandlerContext ctx, SocketAddress remoteAddress, + SocketAddress localAddress, ChannelPromise promise) throws Exception; + + /** + * Called once a disconnect operation is made. + * + * @param ctx the {@link ChannelHandlerContext} for which the disconnect operation is made + * @param promise the {@link ChannelPromise} to notify once the operation completes + * @throws Exception thrown if an error accour + */ + void disconnect(ChannelHandlerContext ctx, ChannelPromise promise) throws Exception; + + /** + * Called once a close operation is made. + * + * @param ctx the {@link ChannelHandlerContext} for which the close operation is made + * @param promise the {@link ChannelPromise} to notify once the operation completes + * @throws Exception thrown if an error accour + */ + void close(ChannelHandlerContext ctx, ChannelPromise promise) throws Exception; + + /** + * Called once a deregister operation is made from the current registered {@link EventLoop}. + * + * @param ctx the {@link ChannelHandlerContext} for which the close operation is made + * @param promise the {@link ChannelPromise} to notify once the operation completes + * @throws Exception thrown if an error accour + */ + void deregister(ChannelHandlerContext ctx, ChannelPromise promise) throws Exception; + + /** + * Intercepts {@link ChannelHandlerContext#read()}. + */ + void read(ChannelHandlerContext ctx) throws Exception; + + /** + * Called once a flush operation is made and so the outbound data should be written. + * + * + * @param ctx the {@link ChannelHandlerContext} for which the flush operation is made + * @param promise the {@link ChannelPromise} to notify once the operation completes + * @throws Exception thrown if an error accour + */ + void write(ChannelHandlerContext ctx, MessageList msgs, ChannelPromise promise) throws Exception; } diff --git a/transport/src/main/java/io/netty/channel/ChannelOperationHandlerAdapter.java b/transport/src/main/java/io/netty/channel/ChannelOutboundHandlerAdapter.java similarity index 68% rename from transport/src/main/java/io/netty/channel/ChannelOperationHandlerAdapter.java rename to transport/src/main/java/io/netty/channel/ChannelOutboundHandlerAdapter.java index 7b314b0396..abc11403be 100644 --- a/transport/src/main/java/io/netty/channel/ChannelOperationHandlerAdapter.java +++ b/transport/src/main/java/io/netty/channel/ChannelOutboundHandlerAdapter.java @@ -18,14 +18,14 @@ package io.netty.channel; import java.net.SocketAddress; /** - * Skelton implementation of a {@link ChannelOperationHandler}. This implementation just forwards each method call via + * Skelton implementation of a {@link ChannelOutboundHandler}. This implementation just forwards each method call via * the {@link ChannelHandlerContext}. */ -public abstract class ChannelOperationHandlerAdapter extends ChannelHandlerAdapter implements ChannelOperationHandler { +public class ChannelOutboundHandlerAdapter extends ChannelHandlerAdapter implements ChannelOutboundHandler { /** * Calls {@link ChannelHandlerContext#bind(SocketAddress, ChannelPromise)} to forward - * to the next {@link ChannelOperationHandler} in the {@link ChannelPipeline}. + * to the next {@link ChannelOutboundHandler} in the {@link ChannelPipeline}. * * Sub-classes may override this method to change behavior. */ @@ -37,7 +37,7 @@ public abstract class ChannelOperationHandlerAdapter extends ChannelHandlerAdapt /** * Calls {@link ChannelHandlerContext#connect(SocketAddress, SocketAddress, ChannelPromise)} to forward - * to the next {@link ChannelOperationHandler} in the {@link ChannelPipeline}. + * to the next {@link ChannelOutboundHandler} in the {@link ChannelPipeline}. * * Sub-classes may override this method to change behavior. */ @@ -49,7 +49,7 @@ public abstract class ChannelOperationHandlerAdapter extends ChannelHandlerAdapt /** * Calls {@link ChannelHandlerContext#disconnect(ChannelPromise)} to forward - * to the next {@link ChannelOperationHandler} in the {@link ChannelPipeline}. + * to the next {@link ChannelOutboundHandler} in the {@link ChannelPipeline}. * * Sub-classes may override this method to change behavior. */ @@ -61,7 +61,7 @@ public abstract class ChannelOperationHandlerAdapter extends ChannelHandlerAdapt /** * Calls {@link ChannelHandlerContext#close(ChannelPromise)} to forward - * to the next {@link ChannelOperationHandler} in the {@link ChannelPipeline}. + * to the next {@link ChannelOutboundHandler} in the {@link ChannelPipeline}. * * Sub-classes may override this method to change behavior. */ @@ -73,35 +73,28 @@ public abstract class ChannelOperationHandlerAdapter extends ChannelHandlerAdapt /** * Calls {@link ChannelHandlerContext#close(ChannelPromise)} to forward - * to the next {@link ChannelOperationHandler} in the {@link ChannelPipeline}. + * to the next {@link ChannelOutboundHandler} in the {@link ChannelPipeline}. * * Sub-classes may override this method to change behavior. */ @Override - public void deregister(ChannelHandlerContext ctx, ChannelPromise promise) - throws Exception { + public void deregister(ChannelHandlerContext ctx, ChannelPromise promise) throws Exception { ctx.deregister(promise); } /** * Calls {@link ChannelHandlerContext#read()} to forward - * to the next {@link ChannelOperationHandler} in the {@link ChannelPipeline}. + * to the next {@link ChannelOutboundHandler} in the {@link ChannelPipeline}. * * Sub-classes may override this method to change behavior. */ @Override - public void read(ChannelHandlerContext ctx) { + public void read(ChannelHandlerContext ctx) throws Exception { ctx.read(); } - /** - * Calls {@link ChannelHandlerContext#sendFile(FileRegion, ChannelPromise)} to forward - * to the next {@link ChannelOperationHandler} in the {@link ChannelPipeline}. - * - * Sub-classes may override this method to change behavior. - */ @Override - public void sendFile(ChannelHandlerContext ctx, FileRegion region, ChannelPromise promise) throws Exception { - ctx.sendFile(region, promise); + public void write(ChannelHandlerContext ctx, MessageList msgs, ChannelPromise promise) throws Exception { + ctx.write(msgs, promise); } } diff --git a/transport/src/main/java/io/netty/channel/ChannelOutboundInvoker.java b/transport/src/main/java/io/netty/channel/ChannelOutboundInvoker.java index ed922b20e0..4f16f90aec 100644 --- a/transport/src/main/java/io/netty/channel/ChannelOutboundInvoker.java +++ b/transport/src/main/java/io/netty/channel/ChannelOutboundInvoker.java @@ -29,8 +29,8 @@ interface ChannelOutboundInvoker { * completes, either because the operation was successful or because of an error. *

* This will result in having the - * {@link ChannelOperationHandler#bind(ChannelHandlerContext, SocketAddress, ChannelPromise)} method - * called of the next {@link ChannelOperationHandler} contained in the {@link ChannelPipeline} of the + * {@link ChannelOutboundHandler#bind(ChannelHandlerContext, SocketAddress, ChannelPromise)} method + * called of the next {@link ChannelOutboundHandler} contained in the {@link ChannelPipeline} of the * {@link Channel}. */ ChannelFuture bind(SocketAddress localAddress); @@ -44,8 +44,8 @@ interface ChannelOutboundInvoker { * will be used. *

* This will result in having the - * {@link ChannelOperationHandler#connect(ChannelHandlerContext, SocketAddress, SocketAddress, ChannelPromise)} - * method called of the next {@link ChannelOperationHandler} contained in the {@link ChannelPipeline} of the + * {@link ChannelOutboundHandler#connect(ChannelHandlerContext, SocketAddress, SocketAddress, ChannelPromise)} + * method called of the next {@link ChannelOutboundHandler} contained in the {@link ChannelPipeline} of the * {@link Channel}. */ ChannelFuture connect(SocketAddress remoteAddress); @@ -56,8 +56,8 @@ interface ChannelOutboundInvoker { * an error. *

* This will result in having the - * {@link ChannelOperationHandler#connect(ChannelHandlerContext, SocketAddress, SocketAddress, ChannelPromise)} - * method called of the next {@link ChannelOperationHandler} contained in the {@link ChannelPipeline} of the + * {@link ChannelOutboundHandler#connect(ChannelHandlerContext, SocketAddress, SocketAddress, ChannelPromise)} + * method called of the next {@link ChannelOutboundHandler} contained in the {@link ChannelPipeline} of the * {@link Channel}. */ ChannelFuture connect(SocketAddress remoteAddress, SocketAddress localAddress); @@ -67,8 +67,8 @@ interface ChannelOutboundInvoker { * either because the operation was successful or because of an error. *

* This will result in having the - * {@link ChannelOperationHandler#disconnect(ChannelHandlerContext, ChannelPromise)} - * method called of the next {@link ChannelOperationHandler} contained in the {@link ChannelPipeline} of the + * {@link ChannelOutboundHandler#disconnect(ChannelHandlerContext, ChannelPromise)} + * method called of the next {@link ChannelOutboundHandler} contained in the {@link ChannelPipeline} of the * {@link Channel}. */ ChannelFuture disconnect(); @@ -81,8 +81,8 @@ interface ChannelOutboundInvoker { * After it is closed it is not possible to reuse it again. *

* This will result in having the - * {@link ChannelOperationHandler#close(ChannelHandlerContext, ChannelPromise)} - * method called of the next {@link ChannelOperationHandler} contained in the {@link ChannelPipeline} of the + * {@link ChannelOutboundHandler#close(ChannelHandlerContext, ChannelPromise)} + * method called of the next {@link ChannelOutboundHandler} contained in the {@link ChannelPipeline} of the * {@link Channel}. */ ChannelFuture close(); @@ -93,31 +93,12 @@ interface ChannelOutboundInvoker { * an error. *

* This will result in having the - * {@link ChannelOperationHandler#deregister(ChannelHandlerContext, ChannelPromise)} - * method called of the next {@link ChannelOperationHandler} contained in the {@link ChannelPipeline} of the + * {@link ChannelOutboundHandler#deregister(ChannelHandlerContext, ChannelPromise)} + * method called of the next {@link ChannelOutboundHandler} contained in the {@link ChannelPipeline} of the * {@link Channel}. */ ChannelFuture deregister(); - /** - * Request to flush all pending data which belongs to this ChannelOutboundInvoker and notify the - * {@link ChannelFuture} once the operation completes, either because the operation was successful or because of - * an error. - *

- * Be aware that the flush could be only partially successful. In such cases the {@link ChannelFuture} will be - * failed with an {@link IncompleteFlushException}. So if you are interested to know if it was partial successful - * you need to check if the returned {@link ChannelFuture#cause()} returns an instance of - * {@link IncompleteFlushException}. In such cases you may want to call {@link #flush(ChannelPromise)} or - * {@link #flush()} to flush the rest of the data or just close the connection via {@link #close(ChannelPromise)} or - * {@link #close()} if it is not possible to recover. - *

- * This will result in having the - * {@link ChannelOperationHandler#flush(ChannelHandlerContext, ChannelPromise)} - * method called of the next {@link ChannelOperationHandler} contained in the {@link ChannelPipeline} of the - * {@link Channel}. - */ - ChannelFuture flush(); - /** * Request to write a message via this ChannelOutboundInvoker and notify the {@link ChannelFuture} * once the operation completes, either because the operation was successful or because of an error. @@ -131,22 +112,12 @@ interface ChannelOutboundInvoker { * or {@link #close()} if it is not possible to recover. *

* This will result in having the message added to the outbound buffer of the next {@link ChannelOutboundHandler} - * and the {@link ChannelOperationHandler#flush(ChannelHandlerContext, ChannelPromise)} - * method called of the next {@link ChannelOperationHandler} contained in the {@link ChannelPipeline} of the + * and the {@link ChannelOutboundHandler#flush(ChannelHandlerContext, ChannelPromise)} + * method called of the next {@link ChannelOutboundHandler} contained in the {@link ChannelPipeline} of the * {@link Channel}. */ - ChannelFuture write(Object message); - - /** - * Request to send a {@link FileRegion} via this ChannelOutboundInvoker and notify the {@link ChannelFuture} - * once the operation completes, either because the operation was successful or because of an error. - *

- * This will result in having the - * {@link ChannelOperationHandler#sendFile(ChannelHandlerContext, FileRegion, ChannelPromise)} - * method called of the next {@link ChannelOperationHandler} contained in the {@link ChannelPipeline} of the - * {@link Channel}. - */ - ChannelFuture sendFile(FileRegion region); + ChannelFuture write(Object msg); + ChannelFuture write(MessageList msgs); /** * Request to bind to the given {@link SocketAddress} and notify the {@link ChannelFuture} once the operation @@ -155,8 +126,8 @@ interface ChannelOutboundInvoker { * The given {@link ChannelPromise} will be notified. *

* This will result in having the - * {@link ChannelOperationHandler#bind(ChannelHandlerContext, SocketAddress, ChannelPromise)} method - * called of the next {@link ChannelOperationHandler} contained in the {@link ChannelPipeline} of the + * {@link ChannelOutboundHandler#bind(ChannelHandlerContext, SocketAddress, ChannelPromise)} method + * called of the next {@link ChannelOutboundHandler} contained in the {@link ChannelPipeline} of the * {@link Channel}. */ ChannelFuture bind(SocketAddress localAddress, ChannelPromise promise); @@ -173,8 +144,8 @@ interface ChannelOutboundInvoker { * will be used. *

* This will result in having the - * {@link ChannelOperationHandler#connect(ChannelHandlerContext, SocketAddress, SocketAddress, ChannelPromise)} - * method called of the next {@link ChannelOperationHandler} contained in the {@link ChannelPipeline} of the + * {@link ChannelOutboundHandler#connect(ChannelHandlerContext, SocketAddress, SocketAddress, ChannelPromise)} + * method called of the next {@link ChannelOutboundHandler} contained in the {@link ChannelPipeline} of the * {@link Channel}. */ ChannelFuture connect(SocketAddress remoteAddress, ChannelPromise promise); @@ -187,8 +158,8 @@ interface ChannelOutboundInvoker { * The given {@link ChannelPromise} will be notified and also returned. *

* This will result in having the - * {@link ChannelOperationHandler#connect(ChannelHandlerContext, SocketAddress, SocketAddress, ChannelPromise)} - * method called of the next {@link ChannelOperationHandler} contained in the {@link ChannelPipeline} of the + * {@link ChannelOutboundHandler#connect(ChannelHandlerContext, SocketAddress, SocketAddress, ChannelPromise)} + * method called of the next {@link ChannelOutboundHandler} contained in the {@link ChannelPipeline} of the * {@link Channel}. */ ChannelFuture connect(SocketAddress remoteAddress, SocketAddress localAddress, ChannelPromise promise); @@ -200,8 +171,8 @@ interface ChannelOutboundInvoker { * The given {@link ChannelPromise} will be notified. *

* This will result in having the - * {@link ChannelOperationHandler#disconnect(ChannelHandlerContext, ChannelPromise)} - * method called of the next {@link ChannelOperationHandler} contained in the {@link ChannelPipeline} of the + * {@link ChannelOutboundHandler#disconnect(ChannelHandlerContext, ChannelPromise)} + * method called of the next {@link ChannelOutboundHandler} contained in the {@link ChannelPipeline} of the * {@link Channel}. */ ChannelFuture disconnect(ChannelPromise promise); @@ -215,8 +186,8 @@ interface ChannelOutboundInvoker { * The given {@link ChannelPromise} will be notified. *

* This will result in having the - * {@link ChannelOperationHandler#close(ChannelHandlerContext, ChannelPromise)} - * method called of the next {@link ChannelOperationHandler} contained in the {@link ChannelPipeline} of the + * {@link ChannelOutboundHandler#close(ChannelHandlerContext, ChannelPromise)} + * method called of the next {@link ChannelOutboundHandler} contained in the {@link ChannelPipeline} of the * {@link Channel}. */ ChannelFuture close(ChannelPromise promise); @@ -229,48 +200,26 @@ interface ChannelOutboundInvoker { * The given {@link ChannelPromise} will be notified. *

* This will result in having the - * {@link ChannelOperationHandler#deregister(ChannelHandlerContext, ChannelPromise)} - * method called of the next {@link ChannelOperationHandler} contained in the {@link ChannelPipeline} of the + * {@link ChannelOutboundHandler#deregister(ChannelHandlerContext, ChannelPromise)} + * method called of the next {@link ChannelOutboundHandler} contained in the {@link ChannelPipeline} of the * {@link Channel}. */ ChannelFuture deregister(ChannelPromise promise); /** * Request to Read data from the {@link Channel} into the first inbound buffer, triggers an - * {@link ChannelStateHandler#inboundBufferUpdated(ChannelHandlerContext) inboundBufferUpdated} event if data was + * {@link ChannelInboundHandler#inboundBufferUpdated(ChannelHandlerContext) inboundBufferUpdated} event if data was * read, and triggers an - * {@link ChannelStateHandler#channelReadSuspended(ChannelHandlerContext) channelReadSuspended} event so the + * {@link ChannelInboundHandler#channelReadSuspended(ChannelHandlerContext) channelReadSuspended} event so the * handler can decide to continue reading. If there's a pending read operation already, this method does nothing. *

* This will result in having the - * {@link ChannelOperationHandler#read(ChannelHandlerContext)} - * method called of the next {@link ChannelOperationHandler} contained in the {@link ChannelPipeline} of the + * {@link ChannelOutboundHandler#read(ChannelHandlerContext)} + * method called of the next {@link ChannelOutboundHandler} contained in the {@link ChannelPipeline} of the * {@link Channel}. */ void read(); - /** - * Request to flush all pending data which belongs to this ChannelOutboundInvoker and notify the - * {@link ChannelFuture} once the operation completes, either because the operation was successful or because of - * an error. - *

- * Be aware that the flush could be only partially successful. In such cases the {@link ChannelFuture} will be - * failed with an {@link IncompleteFlushException}. So if you are interested to know if it was partial successful - * you need to check if the returned {@link ChannelFuture#cause()} returns an instance of - * {@link IncompleteFlushException}. In such cases you may want to call {@link #flush(ChannelPromise)} or - * {@link #flush()} to flush the rest of the data or just close the connection via {@link #close(ChannelPromise)} or - * {@link #close()} if it is not possible to recover. - * - * The given {@link ChannelPromise} will be notified. - *

- * This will result in having the - * {@link ChannelOperationHandler#flush(ChannelHandlerContext, ChannelPromise)} - * method called of the next {@link ChannelOperationHandler} contained in the {@link ChannelPipeline} of the - * {@link Channel}. - * - */ - ChannelFuture flush(ChannelPromise promise); - /** * Request to write a message via this ChannelOutboundInvoker and notify the {@link ChannelFuture} * once the operation completes, either because the operation was successful or because of an error. @@ -286,22 +235,10 @@ interface ChannelOutboundInvoker { * The given {@link ChannelPromise} will be notified. *

* This will result in having the message added to the outbound buffer of the next {@link ChannelOutboundHandler} - * and the {@link ChannelOperationHandler#flush(ChannelHandlerContext, ChannelPromise)} - * method called of the next {@link ChannelOperationHandler} contained in the {@link ChannelPipeline} of the + * and the {@link ChannelOutboundHandler#flush(ChannelHandlerContext, ChannelPromise)} + * method called of the next {@link ChannelOutboundHandler} contained in the {@link ChannelPipeline} of the * {@link Channel}. */ - ChannelFuture write(Object message, ChannelPromise promise); - - /** - * Request to send a {@link FileRegion} via this ChannelOutboundInvoker and notify the {@link ChannelFuture} - * once the operation completes, either because the operation was successful or because of an error. - * - * The given {@link ChannelPromise} will be notified. - *

- * This will result in having the - * {@link ChannelOperationHandler#sendFile(ChannelHandlerContext, FileRegion, ChannelPromise)} - * method called of the next {@link ChannelOperationHandler} contained in the {@link ChannelPipeline} of the - * {@link Channel}. - */ - ChannelFuture sendFile(FileRegion region, ChannelPromise promise); + ChannelFuture write(Object msg, ChannelPromise promise); + ChannelFuture write(MessageList msgs, ChannelPromise promise); } diff --git a/transport/src/main/java/io/netty/channel/ChannelOutboundMessageHandler.java b/transport/src/main/java/io/netty/channel/ChannelOutboundMessageHandler.java deleted file mode 100644 index eb2a1ad4be..0000000000 --- a/transport/src/main/java/io/netty/channel/ChannelOutboundMessageHandler.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright 2012 The Netty Project - * - * The Netty Project licenses this file to you under the Apache License, - * version 2.0 (the "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. - */ -package io.netty.channel; - -import io.netty.buffer.ByteBuf; -import io.netty.buffer.MessageBuf; - -/** - * ChannelOutboundHandler implementation which operates on messages of a specific type - * by pass them in a {@link MessageBuf} and consume then from there. - * - * If your {@link ChannelOutboundMessageHandler} handles messages of type {@link ByteBuf} or {@link Object} - * and you want to add a {@link ByteBuf} to the next buffer in the {@link ChannelPipeline} use - * {@link ChannelHandlerUtil#addToNextOutboundBuffer(ChannelHandlerContext, Object)}. - * - * @param the message type - */ -public interface ChannelOutboundMessageHandler extends ChannelOutboundHandler { - @Override - MessageBuf newOutboundBuffer(ChannelHandlerContext ctx) throws Exception; -} diff --git a/transport/src/main/java/io/netty/channel/ChannelOutboundMessageHandlerAdapter.java b/transport/src/main/java/io/netty/channel/ChannelOutboundMessageHandlerAdapter.java deleted file mode 100644 index 4889e035a5..0000000000 --- a/transport/src/main/java/io/netty/channel/ChannelOutboundMessageHandlerAdapter.java +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Copyright 2012 The Netty Project - * - * The Netty Project licenses this file to you under the Apache License, - * version 2.0 (the "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. - */ -package io.netty.channel; - -import io.netty.buffer.ByteBuf; -import io.netty.buffer.MessageBuf; -import io.netty.buffer.Unpooled; -import io.netty.channel.ChannelHandlerUtil.SingleOutboundMessageHandler; -import io.netty.util.Signal; -import io.netty.util.internal.TypeParameterMatcher; - -/** - * Abstract base class which handles messages of a specific type. - * - * If your {@link ChannelOutboundMessageHandlerAdapter} handles messages of type {@link ByteBuf} or {@link Object} - * and you want to add a {@link ByteBuf} to the next buffer in the {@link ChannelPipeline} use - * {@link ChannelHandlerUtil#addToNextOutboundBuffer(ChannelHandlerContext, Object)}. - * - *

- * One limitation to keep in mind is that it is not possible to detect the handled message type of you specify - * {@code I} while instance your class. Because of this Netty does not allow to do so and will throw an Exception - * if you try. For this cases you should handle the type detection by your self by override the - * {@link #acceptOutboundMessage(Object)} method and use {@link Object} as type parameter. - * - *

- *    public class GenericHandler<I> extends
- *             {@link ChannelOutboundMessageHandlerAdapter}<{@link Object}> {
- *
- *         {@code @Override}
- *         public void flush({@link ChannelHandlerContext} ctx, {@link Object} message)
- *                 throws {@link Exception} {
- *             I msg = (I) message;
- *             // Do something with the msg
- *             ...
- *             ...
- *         }
- *
- *         {@code @Override}
- *         public boolean acceptOutboundMessage(Object msg) throws Exception {
- *             // Add your check here
- *         }
- *     }
- * 
- * @param The type of the messages to handle - */ -public abstract class ChannelOutboundMessageHandlerAdapter - extends ChannelOperationHandlerAdapter - implements ChannelOutboundMessageHandler, SingleOutboundMessageHandler { - - /** - * Thrown by {@link #flush(ChannelHandlerContext, Object)} to abort message processing. - */ - protected static final Signal ABORT = ChannelHandlerUtil.ABORT; - - private final TypeParameterMatcher msgMatcher; - private boolean closeOnFailedFlush = true; - - protected ChannelOutboundMessageHandlerAdapter() { - msgMatcher = TypeParameterMatcher.find(this, ChannelOutboundMessageHandlerAdapter.class, "I"); - } - - protected ChannelOutboundMessageHandlerAdapter(Class outboundMessageType) { - msgMatcher = TypeParameterMatcher.get(outboundMessageType); - } - - protected final boolean isCloseOnFailedFlush() { - return closeOnFailedFlush; - } - - protected final void setCloseOnFailedFlush(boolean closeOnFailedFlush) { - this.closeOnFailedFlush = closeOnFailedFlush; - } - - @Override - public MessageBuf newOutboundBuffer(ChannelHandlerContext ctx) throws Exception { - return Unpooled.messageBuffer(); - } - - @Override - public final void flush(ChannelHandlerContext ctx, ChannelPromise promise) throws Exception { - ChannelHandlerUtil.handleFlush(ctx, promise, isCloseOnFailedFlush(), this); - } - - @Override - public boolean acceptOutboundMessage(Object msg) throws Exception { - return msgMatcher.match(msg); - } - - @Override - public boolean beginFlush(ChannelHandlerContext ctx) throws Exception { - return true; - } - - @Override - public void endFlush(ChannelHandlerContext ctx) throws Exception { } -} diff --git a/transport/src/main/java/io/netty/channel/ChannelPipeline.java b/transport/src/main/java/io/netty/channel/ChannelPipeline.java index f9f7944dd0..26eb387053 100644 --- a/transport/src/main/java/io/netty/channel/ChannelPipeline.java +++ b/transport/src/main/java/io/netty/channel/ChannelPipeline.java @@ -15,9 +15,7 @@ */ package io.netty.channel; -import io.netty.buffer.Buf; import io.netty.buffer.ByteBuf; -import io.netty.buffer.MessageBuf; import io.netty.util.concurrent.EventExecutorGroup; import java.io.InputStream; @@ -176,46 +174,6 @@ import java.util.NoSuchElementException; public interface ChannelPipeline extends ChannelInboundInvoker, ChannelOutboundInvoker, Iterable> { - /** - * Return the bound {@link MessageBuf} of the first {@link ChannelInboundMessageHandler} in the - * {@link ChannelPipeline}. If no {@link ChannelInboundMessageHandler} exists in the {@link ChannelPipeline} - * it will throw a {@link UnsupportedOperationException}. - *

- * This method can only be called from within the event-loop, otherwise it will throw an - * {@link IllegalStateException}. - */ - MessageBuf inboundMessageBuffer(); - - /** - * Return the bound {@link ByteBuf} of the first {@link ChannelInboundByteHandler} in the - * {@link ChannelPipeline}. If no {@link ChannelInboundByteHandler} exists in the {@link ChannelPipeline} - * it will throw a {@link UnsupportedOperationException}. - *

- * This method can only be called from within the event-loop, otherwise it will throw an - * {@link IllegalStateException}. - */ - ByteBuf inboundByteBuffer(); - - /** - * Return the bound {@link MessageBuf} of the first {@link ChannelOutboundMessageHandler} in the - * {@link ChannelPipeline}. If no {@link ChannelOutboundMessageHandler} exists in the {@link ChannelPipeline} - * it will throw a {@link UnsupportedOperationException}. - *

- * This method can only be called from within the event-loop, otherwise it will throw an - * {@link IllegalStateException}. - */ - MessageBuf outboundMessageBuffer(); - - /** - * Return the bound {@link ByteBuf} of the first {@link ChannelOutboundByteHandler} in the - * {@link ChannelPipeline}. If no {@link ChannelOutboundByteHandler} exists in the {@link ChannelPipeline} - * it will throw a {@link UnsupportedOperationException}. - *

- * This method can only be called from within the event-loop, otherwise it will throw an - * {@link IllegalStateException}. - */ - ByteBuf outboundByteBuffer(); - /** * Inserts a {@link ChannelHandler} at the first position of this pipeline. * @@ -381,9 +339,7 @@ public interface ChannelPipeline extends ChannelInboundInvoker, ChannelOutboundI ChannelPipeline addLast(EventExecutorGroup group, ChannelHandler... handlers); /** - * Removes the specified {@link ChannelHandler} from this pipeline - * and transfer the content of its {@link Buf} to the next - * {@link ChannelHandler} in the {@link ChannelPipeline}. + * Removes the specified {@link ChannelHandler} from this pipeline. * * @param handler the {@link ChannelHandler} to remove * @@ -395,9 +351,7 @@ public interface ChannelPipeline extends ChannelInboundInvoker, ChannelOutboundI ChannelPipeline remove(ChannelHandler handler); /** - * Removes the {@link ChannelHandler} with the specified name from this - * pipeline and transfer the content of its {@link Buf} to the next - * {@link ChannelHandler} in the {@link ChannelPipeline}. + * Removes the {@link ChannelHandler} with the specified name from this pipeline. * * @param name the name under which the {@link ChannelHandler} was stored. * @@ -411,9 +365,7 @@ public interface ChannelPipeline extends ChannelInboundInvoker, ChannelOutboundI ChannelHandler remove(String name); /** - * Removes the {@link ChannelHandler} of the specified type from this - * pipeline and transfer the content of its {@link Buf} to the next - * {@link ChannelHandler} in the {@link ChannelPipeline}. + * Removes the {@link ChannelHandler} of the specified type from this pipeline. * * @param the type of the handler * @param handlerType the type of the handler @@ -430,9 +382,6 @@ public interface ChannelPipeline extends ChannelInboundInvoker, ChannelOutboundI /** * Removes the first {@link ChannelHandler} in this pipeline. * - * All the remaining content in the {@link Buf) (if any) of the {@link ChannelHandler} - * will be discarded. - * * @return the removed handler * * @throws NoSuchElementException @@ -443,9 +392,6 @@ public interface ChannelPipeline extends ChannelInboundInvoker, ChannelOutboundI /** * Removes the last {@link ChannelHandler} in this pipeline. * - * All the remaining content in the {@link Buf) (if any) of the {@link ChannelHandler} - * will be discarded. - * * @return the removed handler * * @throws NoSuchElementException @@ -454,9 +400,7 @@ public interface ChannelPipeline extends ChannelInboundInvoker, ChannelOutboundI ChannelHandler removeLast(); /** - * Replaces the specified {@link ChannelHandler} with a new handler in - * this pipeline and transfer the content of its {@link Buf} to the next - * {@link ChannelHandler} in the {@link ChannelPipeline}. + * Replaces the specified {@link ChannelHandler} with a new handler in this pipeline. * * @param oldHandler the {@link ChannelHandler} to be replaced * @param newName the name under which the replacement should be added @@ -476,9 +420,7 @@ public interface ChannelPipeline extends ChannelInboundInvoker, ChannelOutboundI ChannelPipeline replace(ChannelHandler oldHandler, String newName, ChannelHandler newHandler); /** - * Replaces the {@link ChannelHandler} of the specified name with a new - * handler in this pipeline and transfer the content of its {@link Buf} to the next - * {@link ChannelHandler} in the {@link ChannelPipeline}. + * Replaces the {@link ChannelHandler} of the specified name with a new handler in this pipeline. * * @param oldName the name of the {@link ChannelHandler} to be replaced * @param newName the name under which the replacement should be added @@ -498,9 +440,7 @@ public interface ChannelPipeline extends ChannelInboundInvoker, ChannelOutboundI ChannelHandler replace(String oldName, String newName, ChannelHandler newHandler); /** - * Replaces the {@link ChannelHandler} of the specified type with a new - * handler in this pipeline and transfer the content of its {@link Buf} to the next - * {@link ChannelHandler} in the {@link ChannelPipeline}. + * Replaces the {@link ChannelHandler} of the specified type with a new handler in this pipeline. * * @param oldHandlerType the type of the handler to be removed * @param newName the name under which the replacement should be added @@ -631,8 +571,14 @@ public interface ChannelPipeline extends ChannelInboundInvoker, ChannelOutboundI ChannelPipeline fireUserEventTriggered(Object event); @Override - ChannelPipeline fireInboundBufferUpdated(); + ChannelPipeline fireMessageReceived(Object msg); + + @Override + ChannelPipeline fireMessageReceived(MessageList msgs); @Override ChannelPipeline fireChannelReadSuspended(); + + @Override + ChannelPipeline fireChannelWritabilityChanged(); } diff --git a/transport/src/main/java/io/netty/channel/ChannelStateHandler.java b/transport/src/main/java/io/netty/channel/ChannelStateHandler.java deleted file mode 100755 index 9ce18bcaff..0000000000 --- a/transport/src/main/java/io/netty/channel/ChannelStateHandler.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright 2012 The Netty Project - * - * The Netty Project licenses this file to you under the Apache License, - * version 2.0 (the "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. - */ -package io.netty.channel; - -/** - * {@link ChannelHandler} which adds callbacks for state changes. This allows the user - * to hook in to state changes easily. - */ -public interface ChannelStateHandler extends ChannelHandler { - - /** - * The {@link Channel} of the {@link ChannelHandlerContext} was registered with its {@link EventLoop} - */ - void channelRegistered(ChannelHandlerContext ctx) throws Exception; - - /** - * The {@link Channel} of the {@link ChannelHandlerContext} was unregistered from its {@link EventLoop} - */ - void channelUnregistered(ChannelHandlerContext ctx) throws Exception; - - /** - * The {@link Channel} of the {@link ChannelHandlerContext} is now active - */ - void channelActive(ChannelHandlerContext ctx) throws Exception; - - /** - * The {@link Channel} of the {@link ChannelHandlerContext} was registered is now inactive and reached its - * end of lifetime. - */ - void channelInactive(ChannelHandlerContext ctx) throws Exception; - - /** - * Invoked when a {@link ChannelHandlerContext#read()} is finished and the inbound buffer of this handler will not - * be updated until another {@link ChannelHandlerContext#read()} request is issued. - */ - void channelReadSuspended(ChannelHandlerContext ctx) throws Exception; - - /** - * The inbound buffer of the {@link ChannelHandlerContext} was updated with new data. - * This means something may be ready to get processed by the actual {@link ChannelStateHandler} - * implementation. It's up to the implementation to consume it or keep it in the buffer - * to wait for more data and consume it later. - */ - void inboundBufferUpdated(ChannelHandlerContext ctx) throws Exception; - - /** - * Gets called if an user event was triggered. - */ - void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception; -} diff --git a/transport/src/main/java/io/netty/channel/CombinedChannelDuplexHandler.java b/transport/src/main/java/io/netty/channel/CombinedChannelDuplexHandler.java index ab7faf2e6c..34dd384fa8 100644 --- a/transport/src/main/java/io/netty/channel/CombinedChannelDuplexHandler.java +++ b/transport/src/main/java/io/netty/channel/CombinedChannelDuplexHandler.java @@ -18,17 +18,18 @@ package io.netty.channel; import java.net.SocketAddress; /** - * Combines a {@link ChannelStateHandler} and a {@link ChannelOperationHandler} into one {@link ChannelHandler}. + * Combines a {@link ChannelInboundHandler} and a {@link ChannelOutboundHandler} into one {@link ChannelHandler}. * */ -public class CombinedChannelDuplexHandler extends ChannelDuplexHandler { +public class CombinedChannelDuplexHandler + extends ChannelDuplexHandler { - private ChannelStateHandler stateHandler; - private ChannelOperationHandler operationHandler; + private I inboundHandler; + private O outboundHandler; /** * Creates a new uninitialized instance. A class that extends this handler must invoke - * {@link #init(ChannelStateHandler, ChannelOperationHandler)} before adding this handler into a + * {@link #init(ChannelInboundHandler, ChannelOutboundHandler)} before adding this handler into a * {@link ChannelPipeline}. */ protected CombinedChannelDuplexHandler() { } @@ -36,8 +37,8 @@ public class CombinedChannelDuplexHandler extends ChannelDuplexHandler { /** * Creates a new instance that combines the specified two handlers into one. */ - public CombinedChannelDuplexHandler(ChannelStateHandler stateHandler, ChannelOperationHandler operationHandler) { - init(stateHandler, operationHandler); + public CombinedChannelDuplexHandler(I inboundHandler, O outboundHandler) { + init(inboundHandler, outboundHandler); } /** @@ -48,141 +49,110 @@ public class CombinedChannelDuplexHandler extends ChannelDuplexHandler { * @throws IllegalArgumentException if the specified handlers cannot be combined into one due to a conflict * in the type hierarchy */ - protected final void init(ChannelStateHandler stateHandler, ChannelOperationHandler operationHandler) { - validate(stateHandler, operationHandler); - this.stateHandler = stateHandler; - this.operationHandler = operationHandler; + protected final void init(I inboundHandler, O outboundHandler) { + validate(inboundHandler, outboundHandler); + this.inboundHandler = inboundHandler; + this.outboundHandler = outboundHandler; } @SuppressWarnings("InstanceofIncompatibleInterface") - private void validate(ChannelStateHandler stateHandler, ChannelOperationHandler operationHandler) { - if (this.stateHandler != null) { + private void validate(I inboundHandler, O outboundHandler) { + if (this.inboundHandler != null) { throw new IllegalStateException( "init() can not be invoked if " + CombinedChannelDuplexHandler.class.getSimpleName() + " was constructed with non-default constructor."); } - if (stateHandler == null) { - throw new NullPointerException("stateHandler"); + if (inboundHandler == null) { + throw new NullPointerException("inboundHandler"); } - if (operationHandler == null) { - throw new NullPointerException("operationHandler"); + if (outboundHandler == null) { + throw new NullPointerException("outboundHandler"); } - if (stateHandler instanceof ChannelOperationHandler) { + if (inboundHandler instanceof ChannelOutboundHandler) { throw new IllegalArgumentException( - "stateHandler must not implement " + - ChannelOperationHandler.class.getSimpleName() + " to get combined."); + "inboundHandler must not implement " + + ChannelOutboundHandler.class.getSimpleName() + " to get combined."); } - if (operationHandler instanceof ChannelStateHandler) { + if (outboundHandler instanceof ChannelInboundHandler) { throw new IllegalArgumentException( - "operationHandler must not implement " + - ChannelStateHandler.class.getSimpleName() + " to get combined."); - } - - if (stateHandler instanceof ChannelInboundByteHandler && !(this instanceof ChannelInboundByteHandler)) { - throw new IllegalStateException( - getClass().getSimpleName() + " must implement " + ChannelInboundByteHandler.class.getSimpleName() + - " if stateHandler implements " + ChannelInboundByteHandler.class.getSimpleName()); - } - - if (stateHandler instanceof ChannelInboundMessageHandler && !(this instanceof ChannelInboundMessageHandler)) { - throw new IllegalStateException( - getClass().getSimpleName() + " must implement " + - ChannelInboundMessageHandler.class.getSimpleName() + " if stateHandler implements " + - ChannelInboundMessageHandler.class.getSimpleName()); - } - - if (operationHandler instanceof ChannelOutboundByteHandler && !(this instanceof ChannelOutboundByteHandler)) { - throw new IllegalStateException( - getClass().getSimpleName() + " must implement " + - ChannelOutboundByteHandler.class.getSimpleName() + " if operationHandler implements " + - ChannelOutboundByteHandler.class.getSimpleName()); - } - - if (operationHandler instanceof ChannelOutboundMessageHandler && - !(this instanceof ChannelOutboundMessageHandler)) { - throw new IllegalStateException( - getClass().getSimpleName() + " must implement " + - ChannelOutboundMessageHandler.class.getSimpleName() + " if operationHandler implements " + - ChannelOutboundMessageHandler.class.getSimpleName()); + "outboundHandler must not implement " + + ChannelInboundHandler.class.getSimpleName() + " to get combined."); } } - protected final ChannelStateHandler stateHandler() { - return stateHandler; + protected final I inboundHandler() { + return inboundHandler; } - protected final ChannelOperationHandler operationHandler() { - return operationHandler; + protected final O outboundHandler() { + return outboundHandler; } @Override public void handlerAdded(ChannelHandlerContext ctx) throws Exception { - if (stateHandler == null) { + if (inboundHandler == null) { throw new IllegalStateException( "init() must be invoked before being added to a " + ChannelPipeline.class.getSimpleName() + " if " + CombinedChannelDuplexHandler.class.getSimpleName() + " was constructed with the default constructor."); } try { - stateHandler.handlerAdded(ctx); + inboundHandler.handlerAdded(ctx); } finally { - operationHandler.handlerAdded(ctx); + outboundHandler.handlerAdded(ctx); } } @Override public void handlerRemoved(ChannelHandlerContext ctx) throws Exception { try { - stateHandler.handlerRemoved(ctx); + inboundHandler.handlerRemoved(ctx); } finally { - operationHandler.handlerRemoved(ctx); + outboundHandler.handlerRemoved(ctx); } } @Override public void channelRegistered(ChannelHandlerContext ctx) throws Exception { - stateHandler.channelRegistered(ctx); + inboundHandler.channelRegistered(ctx); } @Override public void channelUnregistered(ChannelHandlerContext ctx) throws Exception { - stateHandler.channelUnregistered(ctx); + inboundHandler.channelUnregistered(ctx); } @Override public void channelActive(ChannelHandlerContext ctx) throws Exception { - stateHandler.channelActive(ctx); + inboundHandler.channelActive(ctx); } @Override public void channelInactive(ChannelHandlerContext ctx) throws Exception { - stateHandler.channelInactive(ctx); + inboundHandler.channelInactive(ctx); } @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { - stateHandler.exceptionCaught(ctx, cause); + inboundHandler.exceptionCaught(ctx, cause); } @Override public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception { - stateHandler.userEventTriggered(ctx, evt); + inboundHandler.userEventTriggered(ctx, evt); } @Override - public void inboundBufferUpdated(ChannelHandlerContext ctx) throws Exception { - stateHandler.inboundBufferUpdated(ctx); - if (stateHandler instanceof ChannelInboundByteHandler) { - ((ChannelInboundByteHandler) stateHandler).discardInboundReadBytes(ctx); - } + public void messageReceived(ChannelHandlerContext ctx, MessageList msgs) throws Exception { + inboundHandler.messageReceived(ctx, msgs); } @Override public void bind( ChannelHandlerContext ctx, SocketAddress localAddress, ChannelPromise promise) throws Exception { - operationHandler.bind(ctx, localAddress, promise); + outboundHandler.bind(ctx, localAddress, promise); } @Override @@ -190,36 +160,31 @@ public class CombinedChannelDuplexHandler extends ChannelDuplexHandler { ChannelHandlerContext ctx, SocketAddress remoteAddress, SocketAddress localAddress, ChannelPromise promise) throws Exception { - operationHandler.connect(ctx, remoteAddress, localAddress, promise); + outboundHandler.connect(ctx, remoteAddress, localAddress, promise); } @Override public void disconnect(ChannelHandlerContext ctx, ChannelPromise promise) throws Exception { - operationHandler.disconnect(ctx, promise); + outboundHandler.disconnect(ctx, promise); } @Override public void close(ChannelHandlerContext ctx, ChannelPromise promise) throws Exception { - operationHandler.close(ctx, promise); + outboundHandler.close(ctx, promise); } @Override public void deregister(ChannelHandlerContext ctx, ChannelPromise promise) throws Exception { - operationHandler.deregister(ctx, promise); + outboundHandler.deregister(ctx, promise); } @Override - public void read(ChannelHandlerContext ctx) { - operationHandler.read(ctx); + public void read(ChannelHandlerContext ctx) throws Exception { + outboundHandler.read(ctx); } @Override - public void flush(ChannelHandlerContext ctx, ChannelPromise promise) throws Exception { - operationHandler.flush(ctx, promise); - } - - @Override - public void sendFile(ChannelHandlerContext ctx, FileRegion region, ChannelPromise promise) throws Exception { - operationHandler.sendFile(ctx, region, promise); + public void write(ChannelHandlerContext ctx, MessageList msgs, ChannelPromise promise) throws Exception { + outboundHandler.write(ctx, msgs, promise); } } diff --git a/transport/src/main/java/io/netty/channel/DefaultAddressedEnvelope.java b/transport/src/main/java/io/netty/channel/DefaultAddressedEnvelope.java index a9a544c03c..20766e7165 100644 --- a/transport/src/main/java/io/netty/channel/DefaultAddressedEnvelope.java +++ b/transport/src/main/java/io/netty/channel/DefaultAddressedEnvelope.java @@ -16,7 +16,7 @@ package io.netty.channel; -import io.netty.buffer.BufUtil; +import io.netty.buffer.ByteBufUtil; import io.netty.buffer.ReferenceCounted; import io.netty.util.internal.StringUtil; @@ -82,24 +82,24 @@ public class DefaultAddressedEnvelope implements Add @Override public AddressedEnvelope retain() { - BufUtil.retain(message); + ByteBufUtil.retain(message); return this; } @Override public AddressedEnvelope retain(int increment) { - BufUtil.retain(message, increment); + ByteBufUtil.retain(message, increment); return this; } @Override public boolean release() { - return BufUtil.release(message); + return ByteBufUtil.release(message); } @Override public boolean release(int decrement) { - return BufUtil.release(message, decrement); + return ByteBufUtil.release(message, decrement); } @Override diff --git a/transport/src/main/java/io/netty/channel/DefaultChannelConfig.java b/transport/src/main/java/io/netty/channel/DefaultChannelConfig.java index febf689089..3138aeba67 100644 --- a/transport/src/main/java/io/netty/channel/DefaultChannelConfig.java +++ b/transport/src/main/java/io/netty/channel/DefaultChannelConfig.java @@ -31,15 +31,18 @@ import static io.netty.channel.ChannelOption.*; public class DefaultChannelConfig implements ChannelConfig { private static final ByteBufAllocator DEFAULT_ALLOCATOR = PooledByteBufAllocator.DEFAULT; + private static final RecvByteBufAllocator DEFAULT_RCVBUF_ALLOCATOR = AdaptiveRecvByteBufAllocator.DEFAULT; private static final int DEFAULT_CONNECT_TIMEOUT = 30000; protected final Channel channel; - private volatile ChannelHandlerByteBufType handlerByteBufType = ChannelHandlerByteBufType.PREFER_DIRECT; private volatile ByteBufAllocator allocator = DEFAULT_ALLOCATOR; + private volatile RecvByteBufAllocator rcvBufAllocator = DEFAULT_RCVBUF_ALLOCATOR; private volatile int connectTimeoutMillis = DEFAULT_CONNECT_TIMEOUT; private volatile int writeSpinCount = 16; private volatile boolean autoRead = true; + private volatile int writeBufferHighWaterMark = 64 * 1024; + private volatile int writeBufferLowWaterMark = 32 * 1024; public DefaultChannelConfig(Channel channel) { if (channel == null) { @@ -50,8 +53,7 @@ public class DefaultChannelConfig implements ChannelConfig { @Override public Map, Object> getOptions() { - return getOptions(null, CONNECT_TIMEOUT_MILLIS, WRITE_SPIN_COUNT, ALLOCATOR, AUTO_READ, - DEFAULT_HANDLER_BYTEBUF_TYPE); + return getOptions(null, CONNECT_TIMEOUT_MILLIS, WRITE_SPIN_COUNT, ALLOCATOR, AUTO_READ, RCVBUF_ALLOCATOR); } protected Map, Object> getOptions( @@ -98,12 +100,12 @@ public class DefaultChannelConfig implements ChannelConfig { if (option == ALLOCATOR) { return (T) getAllocator(); } + if (option == RCVBUF_ALLOCATOR) { + return (T) getRecvByteBufAllocator(); + } if (option == AUTO_READ) { return (T) Boolean.valueOf(isAutoRead()); } - if (option == DEFAULT_ALLOCATOR) { - return (T) getDefaultHandlerByteBufType(); - } return null; } @@ -118,10 +120,10 @@ public class DefaultChannelConfig implements ChannelConfig { setWriteSpinCount((Integer) value); } else if (option == ALLOCATOR) { setAllocator((ByteBufAllocator) value); + } else if (option == RCVBUF_ALLOCATOR) { + setRecvByteBufAllocator((RecvByteBufAllocator) value); } else if (option == AUTO_READ) { setAutoRead((Boolean) value); - } else if (option == DEFAULT_HANDLER_BYTEBUF_TYPE) { - setDefaultHandlerByteBufType((ChannelHandlerByteBufType) value); } else { return false; } @@ -180,6 +182,20 @@ public class DefaultChannelConfig implements ChannelConfig { return this; } + @Override + public RecvByteBufAllocator getRecvByteBufAllocator() { + return rcvBufAllocator; + } + + @Override + public ChannelConfig setRecvByteBufAllocator(RecvByteBufAllocator allocator) { + if (allocator == null) { + throw new NullPointerException("allocator"); + } + rcvBufAllocator = allocator; + return this; + } + @Override public boolean isAutoRead() { return autoRead; @@ -196,13 +212,44 @@ public class DefaultChannelConfig implements ChannelConfig { } @Override - public ChannelHandlerByteBufType getDefaultHandlerByteBufType() { - return handlerByteBufType; + public int getWriteBufferHighWaterMark() { + return writeBufferHighWaterMark; } @Override - public ChannelConfig setDefaultHandlerByteBufType(ChannelHandlerByteBufType handlerByteBufType) { - this.handlerByteBufType = handlerByteBufType; + public ChannelConfig setWriteBufferHighWaterMark(int writeBufferHighWaterMark) { + if (writeBufferHighWaterMark < getWriteBufferLowWaterMark()) { + throw new IllegalArgumentException( + "writeBufferHighWaterMark cannot be less than " + + "writeBufferLowWaterMark (" + getWriteBufferLowWaterMark() + "): " + + writeBufferHighWaterMark); + } + if (writeBufferHighWaterMark < 0) { + throw new IllegalArgumentException( + "writeBufferHighWaterMark must be >= 0"); + } + this.writeBufferHighWaterMark = writeBufferHighWaterMark; + return this; + } + + @Override + public int getWriteBufferLowWaterMark() { + return writeBufferLowWaterMark; + } + + @Override + public ChannelConfig setWriteBufferLowWaterMark(int writeBufferLowWaterMark) { + if (writeBufferLowWaterMark > getWriteBufferHighWaterMark()) { + throw new IllegalArgumentException( + "writeBufferLowWaterMark cannot be greater than " + + "writeBufferHighWaterMark (" + getWriteBufferHighWaterMark() + "): " + + writeBufferLowWaterMark); + } + if (writeBufferLowWaterMark < 0) { + throw new IllegalArgumentException( + "writeBufferLowWaterMark must be >= 0"); + } + this.writeBufferLowWaterMark = writeBufferLowWaterMark; return this; } } diff --git a/transport/src/main/java/io/netty/channel/DefaultChannelHandlerContext.java b/transport/src/main/java/io/netty/channel/DefaultChannelHandlerContext.java index 5f32964e45..9a2f2fa4e5 100755 --- a/transport/src/main/java/io/netty/channel/DefaultChannelHandlerContext.java +++ b/transport/src/main/java/io/netty/channel/DefaultChannelHandlerContext.java @@ -15,34 +15,17 @@ */ package io.netty.channel; -import io.netty.buffer.Buf; -import io.netty.buffer.BufType; -import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBufAllocator; -import io.netty.buffer.MessageBuf; -import io.netty.buffer.Unpooled; import io.netty.util.DefaultAttributeMap; import io.netty.util.concurrent.EventExecutor; import io.netty.util.concurrent.EventExecutorGroup; -import io.netty.util.concurrent.Future; -import io.netty.util.internal.PlatformDependent; import java.net.SocketAddress; -import java.nio.channels.ClosedChannelException; -import java.util.Queue; -import java.util.concurrent.ConcurrentLinkedQueue; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.atomic.AtomicReferenceFieldUpdater; import static io.netty.channel.DefaultChannelPipeline.*; final class DefaultChannelHandlerContext extends DefaultAttributeMap implements ChannelHandlerContext { - private static final int FLAG_REMOVED = 1; - private static final int FLAG_FREED = 2; - private static final int FLAG_FREED_INBOUND = 4; - private static final int FLAG_FREED_OUTBOUND = 8; - volatile DefaultChannelHandlerContext next; volatile DefaultChannelHandlerContext prev; @@ -56,48 +39,10 @@ final class DefaultChannelHandlerContext extends DefaultAttributeMap implements final EventExecutor executor; private ChannelFuture succeededFuture; - private final MessageBuf inMsgBuf; - private final ByteBuf inByteBuf; - private MessageBuf outMsgBuf; - private ByteBuf outByteBuf; - private short callDepth; - private short flags; - - // When the two handlers run in a different thread and they are next to each other, - // each other's buffers can be accessed at the same time resulting in a race condition. - // To avoid such situation, we lazily creates an additional thread-safe buffer called - // 'bridge' so that the two handlers access each other's buffer only via the bridges. - // The content written into a bridge is flushed into the actual buffer by flushBridge(). - // - // Note we use an AtomicReferenceFieldUpdater for atomic operations on these to save memory. This will save us - // 64 bytes per Bridge. - @SuppressWarnings("UnusedDeclaration") - private volatile Queue inBridge; - @SuppressWarnings("UnusedDeclaration") - private volatile Queue outBridge; - @SuppressWarnings("UnusedDeclaration") - private volatile NextBridgeFeeder nextInBridgeFeeder; - @SuppressWarnings("UnusedDeclaration") - private volatile NextBridgeFeeder nextOutBridgeFeeder; - - @SuppressWarnings("rawtypes") - private static final AtomicReferenceFieldUpdater IN_BRIDGE_UPDATER = - AtomicReferenceFieldUpdater.newUpdater(DefaultChannelHandlerContext.class, Queue.class, "inBridge"); - @SuppressWarnings("rawtypes") - private static final AtomicReferenceFieldUpdater OUT_BRIDGE_UPDATER = - AtomicReferenceFieldUpdater.newUpdater(DefaultChannelHandlerContext.class, Queue.class, "outBridge"); - private static final AtomicReferenceFieldUpdater - NEXT_IN_BRIDGE_FEEDER = AtomicReferenceFieldUpdater.newUpdater( - DefaultChannelHandlerContext.class, NextBridgeFeeder.class, "nextInBridgeFeeder"); - private static final AtomicReferenceFieldUpdater - NEXT_OUT_BRIDGE_FEEDER = AtomicReferenceFieldUpdater.newUpdater( - DefaultChannelHandlerContext.class, NextBridgeFeeder.class, "nextOutBridgeFeeder"); - // Lazily instantiated tasks used to trigger events to a handler with different executor. - private Runnable invokeInboundBufferUpdatedTask; - private Runnable fireInboundBufferUpdated0Task; private Runnable invokeChannelReadSuspendedTask; private Runnable invokeRead0Task; + private Runnable invokeChannelWritableStateChangedTask; @SuppressWarnings("unchecked") DefaultChannelHandlerContext( @@ -127,340 +72,6 @@ final class DefaultChannelHandlerContext extends DefaultAttributeMap implements } else { executor = null; } - - if (handler instanceof ChannelInboundHandler) { - Buf buf; - try { - buf = ((ChannelInboundHandler) handler).newInboundBuffer(this); - } catch (Exception e) { - throw new ChannelPipelineException( - handler.getClass().getSimpleName() + ".newInboundBuffer() raised an exception.", e); - } - - if (buf instanceof ByteBuf) { - inByteBuf = (ByteBuf) buf; - inMsgBuf = null; - } else if (buf instanceof MessageBuf) { - inMsgBuf = (MessageBuf) buf; - inByteBuf = null; - } else { - throw new ChannelPipelineException( - handler.getClass().getSimpleName() + ".newInboundBuffer() returned neither " + - ByteBuf.class.getSimpleName() + " nor " + MessageBuf.class.getSimpleName() + ": " + buf); - } - } else { - inByteBuf = null; - inMsgBuf = null; - } - - if (handler instanceof ChannelOutboundHandler) { - Buf buf; - try { - buf = ((ChannelOutboundHandler) handler).newOutboundBuffer(this); - } catch (Exception e) { - throw new ChannelPipelineException( - handler.getClass().getSimpleName() + ".newOutboundBuffer() raised an exception.", e); - } - - if (buf instanceof ByteBuf) { - outByteBuf = (ByteBuf) buf; - } else if (buf instanceof MessageBuf) { - @SuppressWarnings("unchecked") - MessageBuf msgBuf = (MessageBuf) buf; - outMsgBuf = msgBuf; - } else { - throw new ChannelPipelineException( - handler.getClass().getSimpleName() + ".newOutboundBuffer() returned neither " + - ByteBuf.class.getSimpleName() + " nor " + MessageBuf.class.getSimpleName() + ": " + buf); - } - } - } - - DefaultChannelHandlerContext(DefaultChannelPipeline pipeline, String name, HeadHandler handler) { - channel = pipeline.channel; - this.pipeline = pipeline; - this.name = name; - this.handler = handler; - executor = null; - inByteBuf = null; - inMsgBuf = null; - } - - DefaultChannelHandlerContext(DefaultChannelPipeline pipeline, String name, TailHandler handler) { - channel = pipeline.channel; - this.pipeline = pipeline; - this.name = name; - this.handler = handler; - executor = null; - inByteBuf = handler.byteSink; - inMsgBuf = handler.msgSink; - outByteBuf = null; - outMsgBuf = null; - } - - void forwardBufferContentAndFree( - final DefaultChannelHandlerContext forwardPrev, final DefaultChannelHandlerContext forwardNext) { - - boolean flush = false; - boolean inboundBufferUpdated = false; - try { - if (!isOutboundFreed()) { - if (hasOutboundByteBuffer() && outboundByteBuffer().isReadable()) { - ByteBuf forwardPrevBuf; - if (forwardPrev.hasOutboundByteBuffer()) { - forwardPrevBuf = forwardPrev.outboundByteBuffer(); - } else { - forwardPrevBuf = forwardPrev.nextOutboundByteBuffer(); - } - forwardPrevBuf.writeBytes(outboundByteBuffer()); - flush = true; - } - if (hasOutboundMessageBuffer() && !outboundMessageBuffer().isEmpty()) { - MessageBuf forwardPrevBuf; - if (forwardPrev.hasOutboundMessageBuffer()) { - forwardPrevBuf = forwardPrev.outboundMessageBuffer(); - } else { - forwardPrevBuf = forwardPrev.nextOutboundMessageBuffer(); - } - if (outboundMessageBuffer().drainTo(forwardPrevBuf) > 0) { - flush = true; - } - } - } - - if (!isInboundFreed()) { - if (hasInboundByteBuffer() && inboundByteBuffer().isReadable()) { - ByteBuf forwardNextBuf; - if (forwardNext.hasInboundByteBuffer()) { - forwardNextBuf = forwardNext.inboundByteBuffer(); - } else { - forwardNextBuf = forwardNext.nextInboundByteBuffer(); - } - forwardNextBuf.writeBytes(inboundByteBuffer()); - inboundBufferUpdated = true; - } - if (hasInboundMessageBuffer() && !inboundMessageBuffer().isEmpty()) { - MessageBuf forwardNextBuf; - if (forwardNext.hasInboundMessageBuffer()) { - forwardNextBuf = forwardNext.inboundMessageBuffer(); - } else { - forwardNextBuf = forwardNext.nextInboundMessageBuffer(); - } - if (inboundMessageBuffer().drainTo(forwardNextBuf) > 0) { - inboundBufferUpdated = true; - } - } - } - } finally { - flags |= FLAG_REMOVED; - freeAllIfRemoved(); - } - - if (flush) { - EventExecutor executor = executor(); - Thread currentThread = Thread.currentThread(); - if (executor.inEventLoop(currentThread)) { - invokePrevFlush(newPromise(), currentThread, findContextOutboundInclusive(forwardPrev)); - } else { - executor.execute(new Runnable() { - @Override - public void run() { - invokePrevFlush(newPromise(), Thread.currentThread(), - findContextOutboundInclusive(forwardPrev)); - } - }); - } - } - - if (inboundBufferUpdated) { - EventExecutor executor = executor(); - if (executor.inEventLoop()) { - fireInboundBufferUpdated0(findContextInboundInclusive(forwardNext)); - } else { - executor.execute(new Runnable() { - @Override - public void run() { - fireInboundBufferUpdated0(findContextInboundInclusive(forwardNext)); - } - }); - } - } - } - - private static DefaultChannelHandlerContext findContextOutboundInclusive(DefaultChannelHandlerContext ctx) { - if (ctx.handler() instanceof ChannelOperationHandler) { - return ctx; - } - return ctx.findContextOutbound(); - } - - private static DefaultChannelHandlerContext findContextInboundInclusive(DefaultChannelHandlerContext ctx) { - if (ctx.handler() instanceof ChannelStateHandler) { - return ctx; - } - return ctx.findContextInbound(); - } - - void clearBuffer() { - if (hasOutboundByteBuffer()) { - outboundByteBuffer().clear(); - } - if (hasOutboundMessageBuffer()) { - outboundMessageBuffer().clear(); - } - if (hasInboundByteBuffer()) { - inboundByteBuffer().clear(); - } - if (hasInboundMessageBuffer()) { - inboundMessageBuffer().clear(); - } - } - - void initHeadHandler() { - // Must be called for the head handler. - EventExecutor executor = executor(); - if (executor.inEventLoop()) { - HeadHandler h = (HeadHandler) handler; - if (h.initialized) { - return; - } - - h.init(this); - h.initialized = true; - outByteBuf = h.byteSink; - outMsgBuf = h.msgSink; - } else { - Future f = executor.submit(new Runnable() { - @Override - public void run() { - initHeadHandler(); - } - }); - - boolean interrupted = false; - try { - while (!f.isDone()) { - try { - f.get(); - } catch (InterruptedException e) { - interrupted = true; - } catch (ExecutionException e) { - PlatformDependent.throwException(e); - } - } - } finally { - if (interrupted) { - Thread.currentThread().interrupt(); - } - } - } - } - - private boolean flushInboundBridge() { - Queue inBridge = this.inBridge; - if (inBridge == null) { - return true; - } - return flushBridge(inBridge, inMsgBuf, inByteBuf); - } - - private boolean flushOutboundBridge() { - Queue outBridge = this.outBridge; - if (outBridge == null) { - return true; - } - return flushBridge(outBridge, outMsgBuf, outByteBuf); - } - - private static boolean flushBridge(Queue bridge, MessageBuf msgBuf, ByteBuf byteBuf) { - if (bridge == null) { - return true; - } - - boolean nextBufferHadEnoughRoom = true; - for (;;) { - Object o = bridge.peek(); - if (o == null) { - break; - } - - try { - if (o instanceof Object[]) { - Object[] data = (Object[]) o; - int i; - for (i = 0; i < data.length; i ++) { - Object m = data[i]; - if (m == null) { - break; - } - - if (msgBuf.offer(m)) { - data[i] = null; - } else { - System.arraycopy(data, i, data, 0, data.length - i); - for (int j = i + 1; j < data.length; j ++) { - data[j] = null; - } - nextBufferHadEnoughRoom = false; - break; - } - } - } else if (o instanceof ByteBuf) { - ByteBuf data = (ByteBuf) o; - if (byteBuf.writerIndex() > byteBuf.maxCapacity() - data.readableBytes()) { - // The target buffer is not going to be able to accept all data in the bridge. - byteBuf.capacity(byteBuf.maxCapacity()); - byteBuf.writeBytes(data, byteBuf.writableBytes()); - nextBufferHadEnoughRoom = false; - break; - } else { - try { - byteBuf.writeBytes(data); - } finally { - data.release(); - } - } - } else { - throw new Error(); - } - } finally { - if (nextBufferHadEnoughRoom) { - Object removed = bridge.remove(); - assert removed == o; - } - } - } - - return nextBufferHadEnoughRoom; - } - - private boolean isInboundFreed() { - return (flags & FLAG_FREED_INBOUND) != 0; - } - - private boolean isOutboundFreed() { - return (flags & FLAG_FREED_OUTBOUND) != 0; - } - - private void freeAllIfRemoved() { - if (callDepth != 0) { - // Free only when the current context's handler is not being called. - return; - } - - final int flags = this.flags; - if ((flags & FLAG_REMOVED) != 0 && (flags & FLAG_FREED) == 0) { // Removed, but not freed yet - try { - safeFree(inByteBuf); - safeFree(inMsgBuf); - safeFree(outByteBuf); - safeFree(outMsgBuf); - } finally { - this.flags = (short) (flags | FLAG_FREED | FLAG_FREED_INBOUND | FLAG_FREED_OUTBOUND); - freeNextInboundBridgeFeeder(); - freeNextOutboundBridgeFeeder(); - } - } } void freeInbound() { @@ -478,14 +89,6 @@ final class DefaultChannelHandlerContext extends DefaultAttributeMap implements } private void freeInbound0() { - try { - safeFree(inByteBuf); - safeFree(inMsgBuf); - } finally { - flags |= FLAG_FREED_INBOUND; - freeNextInboundBridgeFeeder(); - } - if (next != null) { DefaultChannelHandlerContext nextCtx = findContextInbound(); nextCtx.freeInbound(); @@ -494,90 +97,36 @@ final class DefaultChannelHandlerContext extends DefaultAttributeMap implements // to head (inclusive) to trigger handlerRemoved(). If the removed handler has an outbound buffer, free it, // too. Note that the tail handler is excluded because it's neither an outbound buffer and it doesn't // do anything in handlerRemoved(). - pipeline.tail.prev.freeOutboundAndRemove(); + pipeline.tail.prev.teardown(); } } + void teardownAll() { + pipeline.tail.prev.teardown(); + } + /** Invocation initiated by {@link #freeInbound0()} after freeing all inbound buffers. */ - private void freeOutboundAndRemove() { + private void teardown() { EventExecutor executor = executor(); if (executor.inEventLoop()) { - freeOutboundAndRemove0(); + teardown0(); } else { executor.execute(new Runnable() { @Override public void run() { - freeOutboundAndRemove0(); + teardown0(); } }); } } - private void freeOutboundAndRemove0() { - if (handler instanceof ChannelOperationHandler) { - // Outbound handler - free the buffers / bridge feeders - try { - safeFree(outByteBuf); - safeFree(outMsgBuf); - } finally { - // We also OR FLAG_FREED because at this point we are sure both inbound and outbound were freed. - flags |= FLAG_FREED | FLAG_FREED_OUTBOUND; - freeNextOutboundBridgeFeeder(); - } - } - + private void teardown0() { DefaultChannelHandlerContext prev = this.prev; if (prev != null) { synchronized (pipeline) { - pipeline.remove0(this, false); - } - prev.freeOutboundAndRemove(); - } - } - - private void freeNextInboundBridgeFeeder() { - // Release the bridge feeder - NextBridgeFeeder feeder; - feeder = nextInBridgeFeeder; - if (feeder != null) { - feeder.release(); - nextInBridgeFeeder = null; - } - - // Warn if the bridge has unflushed elements. - if (logger.isWarnEnabled()) { - Queue bridge; - bridge = inBridge; - if (bridge != null && !bridge.isEmpty()) { - logger.warn("inbound bridge not empty - bug?: {}", bridge.size()); - } - } - } - - private void freeNextOutboundBridgeFeeder() { - // Release the bridge feeder - NextBridgeFeeder feeder = nextOutBridgeFeeder; - if (feeder != null) { - feeder.release(); - nextOutBridgeFeeder = null; - } - - // Warn if the bridge has unflushed elements. - if (logger.isWarnEnabled()) { - Queue bridge = outBridge; - if (bridge != null && !bridge.isEmpty()) { - logger.warn("outbound bridge not empty - bug?: {}", bridge.size()); - } - } - } - - private static void safeFree(Buf buf) { - if (buf != null) { - try { - buf.release(); - } catch (Exception e) { - logger.warn("Failed to release a handler buffer.", e); + pipeline.remove0(this); } + prev.teardown(); } } @@ -615,164 +164,6 @@ final class DefaultChannelHandlerContext extends DefaultAttributeMap implements return name; } - @Override - public boolean hasInboundByteBuffer() { - return inByteBuf != null; - } - - @Override - public boolean hasInboundMessageBuffer() { - return inMsgBuf != null; - } - - @Override - public ByteBuf inboundByteBuffer() { - if (inByteBuf == null) { - throw new NoSuchBufferException(String.format( - "the handler '%s' has no inbound byte buffer; it does not implement %s.", - name, ChannelInboundByteHandler.class.getSimpleName())); - } - return inByteBuf; - } - - @Override - @SuppressWarnings("unchecked") - public MessageBuf inboundMessageBuffer() { - if (inMsgBuf == null) { - throw new NoSuchBufferException(String.format( - "the handler '%s' has no inbound message buffer; it does not implement %s.", - name, ChannelInboundMessageHandler.class.getSimpleName())); - } - return (MessageBuf) inMsgBuf; - } - - @Override - public boolean hasOutboundByteBuffer() { - return outByteBuf != null; - } - - @Override - public boolean hasOutboundMessageBuffer() { - return outMsgBuf != null; - } - - @Override - public ByteBuf outboundByteBuffer() { - if (outByteBuf == null) { - throw new NoSuchBufferException(String.format( - "the handler '%s' has no outbound byte buffer; it does not implement %s.", - name, ChannelOutboundByteHandler.class.getSimpleName())); - } - return outByteBuf; - } - - @Override - @SuppressWarnings("unchecked") - public MessageBuf outboundMessageBuffer() { - if (outMsgBuf == null) { - throw new NoSuchBufferException(String.format( - "the handler '%s' has no outbound message buffer; it does not implement %s.", - name, ChannelOutboundMessageHandler.class.getSimpleName())); - } - return (MessageBuf) outMsgBuf; - } - - @Override - public ByteBuf nextInboundByteBuffer() { - DefaultChannelHandlerContext ctx = next; - for (;;) { - if (ctx.hasInboundByteBuffer()) { - Thread currentThread = Thread.currentThread(); - if (ctx.executor().inEventLoop(currentThread)) { - return ctx.inByteBuf; - } - if (executor().inEventLoop(currentThread)) { - return nextInBridgeFeeder().byteBuf; - } - throw new IllegalStateException("nextInboundByteBuffer() called from outside the eventLoop"); - } - ctx = ctx.next; - } - } - - @Override - public MessageBuf nextInboundMessageBuffer() { - DefaultChannelHandlerContext ctx = next; - for (;;) { - if (ctx.hasInboundMessageBuffer()) { - Thread currentThread = Thread.currentThread(); - if (ctx.executor().inEventLoop(currentThread)) { - return ctx.inMsgBuf; - } - if (executor().inEventLoop(currentThread)) { - return nextInBridgeFeeder().msgBuf; - } - throw new IllegalStateException("nextInboundMessageBuffer() called from outside the eventLoop"); - } - ctx = ctx.next; - } - } - - private NextBridgeFeeder nextInBridgeFeeder() { - NextBridgeFeeder feeder = nextInBridgeFeeder; - if (feeder == null) { - feeder = new NextInboundBridgeFeeder(); - if (!NEXT_IN_BRIDGE_FEEDER.compareAndSet(this, null, feeder)) { - feeder.release(); - feeder = nextInBridgeFeeder; - } - } - return feeder; - } - - @Override - public ByteBuf nextOutboundByteBuffer() { - DefaultChannelHandlerContext ctx = prev; - for (;;) { - if (ctx.hasOutboundByteBuffer()) { - Thread currentThread = Thread.currentThread(); - if (ctx.executor().inEventLoop(currentThread)) { - return ctx.outboundByteBuffer(); - } - if (executor().inEventLoop(currentThread)) { - return nextOutBridgeFeeder().byteBuf; - } - throw new IllegalStateException("nextOutboundByteBuffer() called from outside the eventLoop"); - } - ctx = ctx.prev; - } - } - - @Override - public MessageBuf nextOutboundMessageBuffer() { - DefaultChannelHandlerContext ctx = prev; - for (;;) { - if (ctx.hasOutboundMessageBuffer()) { - Thread currentThread = Thread.currentThread(); - if (ctx.executor().inEventLoop(currentThread)) { - return ctx.outboundMessageBuffer(); - } - if (executor().inEventLoop(currentThread)) { - return nextOutBridgeFeeder().msgBuf; - } - throw new IllegalStateException("nextOutboundMessageBuffer() called from outside the eventLoop"); - } - ctx = ctx.prev; - } - } - - private NextBridgeFeeder nextOutBridgeFeeder() { - NextBridgeFeeder feeder = nextOutBridgeFeeder; - if (feeder == null) { - feeder = new NextOutboundBridgeFeeder(); - if (!NEXT_OUT_BRIDGE_FEEDER.compareAndSet(this, null, feeder)) { - feeder.release(); - feeder = nextOutBridgeFeeder; - } - } - return feeder; - } - @Override public ChannelHandlerContext fireChannelRegistered() { final DefaultChannelHandlerContext next = findContextInbound(); @@ -791,14 +182,10 @@ final class DefaultChannelHandlerContext extends DefaultAttributeMap implements } private void invokeChannelRegistered() { - callDepth ++; try { - ((ChannelStateHandler) handler()).channelRegistered(this); + ((ChannelInboundHandler) handler()).channelRegistered(this); } catch (Throwable t) { notifyHandlerException(t); - } finally { - callDepth --; - freeAllIfRemoved(); } } @@ -820,13 +207,10 @@ final class DefaultChannelHandlerContext extends DefaultAttributeMap implements } private void invokeChannelUnregistered() { - callDepth ++; try { - ((ChannelStateHandler) handler()).channelUnregistered(this); + ((ChannelInboundHandler) handler()).channelUnregistered(this); } catch (Throwable t) { notifyHandlerException(t); - } finally { - callDepth --; } } @@ -848,14 +232,10 @@ final class DefaultChannelHandlerContext extends DefaultAttributeMap implements } private void invokeChannelActive() { - callDepth ++; try { - ((ChannelStateHandler) handler()).channelActive(this); + ((ChannelInboundHandler) handler()).channelActive(this); } catch (Throwable t) { notifyHandlerException(t); - } finally { - callDepth --; - freeAllIfRemoved(); } } @@ -877,14 +257,10 @@ final class DefaultChannelHandlerContext extends DefaultAttributeMap implements } private void invokeChannelInactive() { - callDepth ++; try { - ((ChannelStateHandler) handler()).channelInactive(this); + ((ChannelInboundHandler) handler()).channelInactive(this); } catch (Throwable t) { notifyHandlerException(t); - } finally { - callDepth --; - freeAllIfRemoved(); } } @@ -921,7 +297,6 @@ final class DefaultChannelHandlerContext extends DefaultAttributeMap implements private void invokeExceptionCaught0(Throwable cause) { ChannelHandler handler = handler(); - callDepth ++; try { handler.exceptionCaught(this, cause); } catch (Throwable t) { @@ -930,9 +305,6 @@ final class DefaultChannelHandlerContext extends DefaultAttributeMap implements "An exception was thrown by a user handler's " + "exceptionCaught() method while handling the following exception:", cause); } - } finally { - callDepth --; - freeAllIfRemoved(); } } @@ -958,108 +330,54 @@ final class DefaultChannelHandlerContext extends DefaultAttributeMap implements } private void invokeUserEventTriggered(Object event) { - ChannelStateHandler handler = (ChannelStateHandler) handler(); - - callDepth ++; + ChannelInboundHandler handler = (ChannelInboundHandler) handler(); try { handler.userEventTriggered(this, event); } catch (Throwable t) { notifyHandlerException(t); - } finally { - callDepth --; - freeAllIfRemoved(); } } @Override - public ChannelHandlerContext fireInboundBufferUpdated() { - EventExecutor executor = executor(); + public ChannelHandlerContext fireMessageReceived(Object msg) { + if (msg == null) { + throw new NullPointerException("msg"); + } + return fireMessageReceived(MessageList.newInstance(msg)); + } + + @Override + public ChannelHandlerContext fireMessageReceived(final MessageList msgs) { + if (msgs == null) { + throw new NullPointerException("msgs"); + } + + if (msgs.isEmpty()) { + msgs.recycle(); + return this; + } + + final DefaultChannelHandlerContext next = findContextInbound(); + EventExecutor executor = next.executor(); if (executor.inEventLoop()) { - fireInboundBufferUpdated0(findContextInbound()); + next.invokeMessageReceived(msgs); } else { - Runnable task = fireInboundBufferUpdated0Task; - if (task == null) { - fireInboundBufferUpdated0Task = task = new Runnable() { - @Override - public void run() { - fireInboundBufferUpdated0(findContextInbound()); - } - }; - } - executor.execute(task); + executor.execute(new Runnable() { + @Override + public void run() { + next.invokeMessageReceived(msgs); + } + }); } return this; } - private void fireInboundBufferUpdated0(final DefaultChannelHandlerContext next) { - feedNextInBridge(); - // This comparison is safe because this method is always executed from the executor. - if (next.executor == executor) { - next.invokeInboundBufferUpdated(); - } else { - Runnable task = next.invokeInboundBufferUpdatedTask; - if (task == null) { - next.invokeInboundBufferUpdatedTask = task = new Runnable() { - @Override - public void run() { - next.invokeInboundBufferUpdated(); - } - }; - } - next.executor().execute(task); - } - } - - private void feedNextInBridge() { - NextBridgeFeeder feeder = nextInBridgeFeeder; - if (feeder != null) { - feeder.feed(); - } - } - - private void invokeInboundBufferUpdated() { - if (isInboundFreed()) { - return; - } - - ChannelStateHandler handler = (ChannelStateHandler) handler(); - if (handler instanceof ChannelInboundHandler) { - for (;;) { - callDepth ++; - try { - boolean flushedAll = flushInboundBridge(); - handler.inboundBufferUpdated(this); - if (flushedAll) { - break; - } - } catch (Throwable t) { - notifyHandlerException(t); - break; - } finally { - callDepth --; - if (handler instanceof ChannelInboundByteHandler && !isInboundFreed()) { - try { - ((ChannelInboundByteHandler) handler).discardInboundReadBytes(this); - } catch (Throwable t) { - notifyHandlerException(t); - } - } - freeAllIfRemoved(); - } - - if (isInboundFreed()) { - break; - } - } - } else { - callDepth ++; - try { - handler.inboundBufferUpdated(this); - } catch (Throwable t) { - notifyHandlerException(t); - } finally { - callDepth --; - } + private void invokeMessageReceived(MessageList msgs) { + ChannelInboundHandler handler = (ChannelInboundHandler) handler(); + try { + handler.messageReceived(this, msgs.cast()); + } catch (Throwable t) { + notifyHandlerException(t); } } @@ -1085,14 +403,39 @@ final class DefaultChannelHandlerContext extends DefaultAttributeMap implements } private void invokeChannelReadSuspended() { - callDepth ++; try { - ((ChannelStateHandler) handler()).channelReadSuspended(this); + ((ChannelInboundHandler) handler()).channelReadSuspended(this); + } catch (Throwable t) { + notifyHandlerException(t); + } + } + + @Override + public ChannelHandlerContext fireChannelWritabilityChanged() { + final DefaultChannelHandlerContext next = findContextInbound(); + EventExecutor executor = next.executor(); + if (executor.inEventLoop()) { + next.invokeChannelWritabilityChanged(); + } else { + Runnable task = next.invokeChannelWritableStateChangedTask; + if (task == null) { + next.invokeChannelWritableStateChangedTask = task = new Runnable() { + @Override + public void run() { + next.invokeChannelReadSuspended(); + } + }; + } + executor.execute(task); + } + return this; + } + + private void invokeChannelWritabilityChanged() { + try { + ((ChannelInboundHandler) handler()).channelWritabilityChanged(this); } catch (Throwable t) { notifyHandlerException(t); - } finally { - callDepth --; - freeAllIfRemoved(); } } @@ -1127,13 +470,13 @@ final class DefaultChannelHandlerContext extends DefaultAttributeMap implements } @Override - public ChannelFuture flush() { - return flush(newPromise()); + public ChannelFuture write(Object msg) { + return write(msg, newPromise()); } @Override - public ChannelFuture write(Object message) { - return write(message, newPromise()); + public ChannelFuture write(MessageList msgs) { + return write(msgs, newPromise()); } @Override @@ -1161,14 +504,10 @@ final class DefaultChannelHandlerContext extends DefaultAttributeMap implements } private void invokeBind0(SocketAddress localAddress, ChannelPromise promise) { - callDepth ++; try { - ((ChannelOperationHandler) handler()).bind(this, localAddress, promise); + ((ChannelOutboundHandler) handler()).bind(this, localAddress, promise); } catch (Throwable t) { - notifyHandlerException(t); - } finally { - callDepth --; - freeAllIfRemoved(); + notifyHandlerException(t, promise); } } @@ -1204,14 +543,10 @@ final class DefaultChannelHandlerContext extends DefaultAttributeMap implements } private void invokeConnect0(SocketAddress remoteAddress, SocketAddress localAddress, ChannelPromise promise) { - callDepth ++; try { - ((ChannelOperationHandler) handler()).connect(this, remoteAddress, localAddress, promise); + ((ChannelOutboundHandler) handler()).connect(this, remoteAddress, localAddress, promise); } catch (Throwable t) { - notifyHandlerException(t); - } finally { - callDepth --; - freeAllIfRemoved(); + notifyHandlerException(t, promise); } } @@ -1245,14 +580,10 @@ final class DefaultChannelHandlerContext extends DefaultAttributeMap implements } private void invokeDisconnect0(ChannelPromise promise) { - callDepth ++; try { - ((ChannelOperationHandler) handler()).disconnect(this, promise); + ((ChannelOutboundHandler) handler()).disconnect(this, promise); } catch (Throwable t) { - notifyHandlerException(t); - } finally { - callDepth --; - freeAllIfRemoved(); + notifyHandlerException(t, promise); } } @@ -1279,14 +610,10 @@ final class DefaultChannelHandlerContext extends DefaultAttributeMap implements } private void invokeClose0(ChannelPromise promise) { - callDepth ++; try { - ((ChannelOperationHandler) handler()).close(this, promise); + ((ChannelOutboundHandler) handler()).close(this, promise); } catch (Throwable t) { - notifyHandlerException(t); - } finally { - callDepth --; - freeAllIfRemoved(); + notifyHandlerException(t, promise); } } @@ -1313,14 +640,10 @@ final class DefaultChannelHandlerContext extends DefaultAttributeMap implements } private void invokeDeregister0(ChannelPromise promise) { - callDepth ++; try { - ((ChannelOperationHandler) handler()).deregister(this, promise); + ((ChannelOutboundHandler) handler()).deregister(this, promise); } catch (Throwable t) { - notifyHandlerException(t); - } finally { - callDepth --; - freeAllIfRemoved(); + notifyHandlerException(t, promise); } } @@ -1348,124 +671,37 @@ final class DefaultChannelHandlerContext extends DefaultAttributeMap implements } private void invokeRead0() { - callDepth ++; try { - ((ChannelOperationHandler) handler()).read(this); + ((ChannelOutboundHandler) handler()).read(this); } catch (Throwable t) { notifyHandlerException(t); - } finally { - callDepth --; - freeAllIfRemoved(); } } @Override - public ChannelFuture flush(final ChannelPromise promise) { + public ChannelFuture write(Object msg, final ChannelPromise promise) { + if (msg == null) { + throw new NullPointerException("msg"); + } + return write(MessageList.newInstance(msg), promise); + } + + @Override + public ChannelFuture write(MessageList msgs, ChannelPromise promise) { + return findContextOutbound().invokeWrite(msgs, promise); + } + + private ChannelFuture invokeWrite(final MessageList msgs, final ChannelPromise promise) { validateFuture(promise, true); - EventExecutor executor = executor(); - Thread currentThread = Thread.currentThread(); - if (executor.inEventLoop(currentThread)) { - invokePrevFlush(promise, currentThread, findContextOutbound()); - } else { - executor.execute(new Runnable() { - @Override - public void run() { - invokePrevFlush(promise, Thread.currentThread(), findContextOutbound()); - } - }); - } - - return promise; - } - - private void invokePrevFlush(ChannelPromise promise, Thread currentThread, DefaultChannelHandlerContext prev) { - feedNextOutBridge(); - prev.invokeFlush(promise, currentThread); - } - - private void feedNextOutBridge() { - NextBridgeFeeder feeder = nextOutBridgeFeeder; - if (feeder != null) { - feeder.feed(); - } - } - - private ChannelFuture invokeFlush(final ChannelPromise promise, Thread currentThread) { - EventExecutor executor = executor(); - if (executor.inEventLoop(currentThread)) { - invokeFlush0(promise); - } else { - executor.execute(new Runnable() { - @Override - public void run() { - invokeFlush0(promise); - } - }); - } - - return promise; - } - - private void invokeFlush0(ChannelPromise promise) { - if (isOutboundFreed()) { - promise.setFailure(new ChannelPipelineException( - "Unable to flush as outbound buffer of next handler was freed already")); - return; - } - - Channel channel = channel(); - if (!channel.isActive() && !channel.isRegistered()) { - promise.setFailure(new ClosedChannelException()); - return; - } - - ChannelOperationHandler handler = (ChannelOperationHandler) handler(); - if (handler instanceof ChannelOutboundHandler) { - flushOutboundBridge(); - } - - callDepth ++; - try { - handler.flush(this, promise); - } catch (Throwable t) { - notifyHandlerException(t); - } finally { - callDepth --; - if (handler instanceof ChannelOutboundByteHandler && !isOutboundFreed()) { - try { - ((ChannelOutboundByteHandler) handler).discardOutboundReadBytes(this); - } catch (Throwable t) { - notifyHandlerException(t); - } - } - freeAllIfRemoved(); - } - } - - @Override - public ChannelFuture sendFile(FileRegion region) { - return sendFile(region, newPromise()); - } - - @Override - public ChannelFuture sendFile(FileRegion region, ChannelPromise promise) { - if (region == null) { - throw new NullPointerException("region"); - } - validateFuture(promise, true); - return findContextOutbound().invokeSendFile(region, promise); - } - - private ChannelFuture invokeSendFile(final FileRegion region, final ChannelPromise promise) { EventExecutor executor = executor(); if (executor.inEventLoop()) { - invokeSendFile0(region, promise); + invokeWrite0(msgs, promise); } else { executor.execute(new Runnable() { @Override public void run() { - invokeSendFile0(region, promise); + invokeWrite0(msgs, promise); } }); } @@ -1473,124 +709,27 @@ final class DefaultChannelHandlerContext extends DefaultAttributeMap implements return promise; } - private void invokeSendFile0(FileRegion region, ChannelPromise promise) { - ChannelOperationHandler handler = (ChannelOperationHandler) handler(); - if (handler instanceof ChannelOutboundHandler) { - flushOutboundBridge(); - } - - callDepth ++; + private void invokeWrite0(MessageList msgs, ChannelPromise promise) { + ChannelOutboundHandler handler = (ChannelOutboundHandler) handler(); try { - handler.sendFile(this, region, promise); + handler.write(this, msgs.cast(), promise); } catch (Throwable t) { - notifyHandlerException(t); - } finally { - callDepth --; - freeAllIfRemoved(); + notifyHandlerException(t, promise); } } - @Override - public ChannelFuture write(final Object message, final ChannelPromise promise) { - if (message instanceof FileRegion) { - return sendFile((FileRegion) message, promise); - } - - if (message == null) { - throw new NullPointerException("message"); - } - validateFuture(promise, true); - - DefaultChannelHandlerContext ctx = prev; - EventExecutor executor = executor(); - final boolean msgBuf; - - if (message instanceof ByteBuf) { - for (;;) { - if (ctx.hasOutboundByteBuffer()) { - msgBuf = false; - executor = ctx.executor(); - break; - } - - if (ctx.hasOutboundMessageBuffer()) { - msgBuf = true; - executor = ctx.executor(); - break; - } - - DefaultChannelHandlerContext prev = ctx.prev; - if (prev == null) { - assert ctx == pipeline.head; - // this means we reached end of pipeline but the head-handler was not yet init. - // in this case init it now and schedule the write via the executor so it is - // done after fireChannelRegistered() completes - // - // See https://github.com/netty/netty/issues/1385 - ctx.initHeadHandler(); - - executor.execute(new Runnable() { - @Override - public void run() { - write(message, promise); - } - }); - return promise; - } else { - ctx = prev; - } + private void notifyHandlerException(Throwable cause, ChannelPromise promise) { + // only try to fail the promise if its not a VoidChannelPromise, as + // the VoidChannelPromise would also fire the cause through the pipeline + if (!(promise instanceof VoidChannelPromise) && !promise.tryFailure(cause)) { + if (logger.isWarnEnabled()) { + logger.warn( + "Failed to fail the promise", cause); } - } else { - msgBuf = true; - for (;;) { - if (ctx.hasOutboundMessageBuffer()) { - executor = ctx.executor(); - break; - } - - ctx = ctx.prev; - } - } - - if (executor.inEventLoop()) { - ctx.write0(message, promise, msgBuf); - return promise; - } - - final DefaultChannelHandlerContext ctx0 = ctx; - executor.execute(new Runnable() { - @Override - public void run() { - ctx0.write0(message, promise, msgBuf); - } - }); - - return promise; - } - - private void write0(Object message, ChannelPromise promise, boolean msgBuf) { - Channel channel = channel(); - if (!channel.isRegistered() && !channel.isActive()) { - promise.setFailure(new ClosedChannelException()); return; } - if (isOutboundFreed()) { - promise.setFailure(new ChannelPipelineException( - "Unable to write as outbound buffer of next handler was freed already")); - return; - } - if (msgBuf) { - outboundMessageBuffer().add(message); - } else { - ByteBuf buf = (ByteBuf) message; - try { - outboundByteBuffer().writeBytes(buf, buf.readerIndex(), buf.readableBytes()); - } finally { - buf.release(); - } - } - invokeFlush0(promise); + notifyHandlerException(cause); } private void notifyHandlerException(Throwable cause) { @@ -1670,170 +809,21 @@ final class DefaultChannelHandlerContext extends DefaultAttributeMap implements } private DefaultChannelHandlerContext findContextInbound() { - DefaultChannelHandlerContext ctx = this; - do { - ctx = ctx.next; - } while (!(ctx.handler() instanceof ChannelStateHandler)); - return ctx; - } - - @Override - public BufType nextInboundBufferType() { DefaultChannelHandlerContext ctx = this; do { ctx = ctx.next; } while (!(ctx.handler() instanceof ChannelInboundHandler)); - - if (ctx.handler() instanceof ChannelInboundByteHandler) { - return BufType.BYTE; - } else { - return BufType.MESSAGE; - } - } - - @Override - public BufType nextOutboundBufferType() { - DefaultChannelHandlerContext ctx = this; - do { - ctx = ctx.prev; - } while (!(ctx.handler() instanceof ChannelOutboundHandler)); - - if (ctx.handler() instanceof ChannelOutboundByteHandler) { - return BufType.BYTE; - } else { - return BufType.MESSAGE; - } + return ctx; } private DefaultChannelHandlerContext findContextOutbound() { DefaultChannelHandlerContext ctx = this; do { ctx = ctx.prev; - } while (!(ctx.handler() instanceof ChannelOperationHandler)); + } while (!(ctx.handler() instanceof ChannelOutboundHandler)); return ctx; } - private abstract class NextBridgeFeeder { - final MessageBuf msgBuf; - final ByteBuf byteBuf; - - protected NextBridgeFeeder() { - msgBuf = Unpooled.messageBuffer(); - byteBuf = ChannelHandlerUtil.allocate(DefaultChannelHandlerContext.this); - } - - final void feed() { - int dataLen = byteBuf.readableBytes(); - if (dataLen != 0) { - ByteBuf data; - if (byteBuf.isDirect()) { - data = alloc().directBuffer(dataLen, dataLen); - } else { - data = alloc().heapBuffer(dataLen, dataLen); - } - - byteBuf.readBytes(data).discardSomeReadBytes(); - nextByteBridge().add(data); - } - - if (!msgBuf.isEmpty()) { - Object[] data = msgBuf.toArray(); - msgBuf.clear(); - nextMessageBridge().add(data); - } - } - - final void release() { - byteBuf.release(); - msgBuf.release(); - } - - protected abstract Queue nextByteBridge(); - protected abstract Queue nextMessageBridge(); - } - - private final class NextInboundBridgeFeeder extends NextBridgeFeeder { - @Override - protected Queue nextByteBridge() { - DefaultChannelHandlerContext ctx = next; - for (;;) { - if (ctx.hasInboundByteBuffer()) { - break; - } - ctx = ctx.next; - } - - return bridge(ctx); - } - - @Override - protected Queue nextMessageBridge() { - DefaultChannelHandlerContext ctx = next; - for (;;) { - if (ctx.hasInboundMessageBuffer()) { - break; - } - ctx = ctx.next; - } - - return bridge(ctx); - } - - private Queue bridge(DefaultChannelHandlerContext ctx) { - Queue bridge = ctx.inBridge; - if (bridge == null) { - Queue newBridge = new ConcurrentLinkedQueue(); - if (IN_BRIDGE_UPDATER.compareAndSet(ctx, null, newBridge)) { - bridge = newBridge; - } else { - bridge = ctx.inBridge; - } - } - return bridge; - } - } - - private final class NextOutboundBridgeFeeder extends NextBridgeFeeder { - @Override - protected Queue nextByteBridge() { - DefaultChannelHandlerContext ctx = prev; - for (;;) { - if (ctx.hasOutboundByteBuffer()) { - break; - } - ctx = ctx.prev; - } - - return bridge(ctx); - } - - @Override - protected Queue nextMessageBridge() { - DefaultChannelHandlerContext ctx = prev; - for (;;) { - if (ctx.hasOutboundMessageBuffer()) { - break; - } - ctx = ctx.prev; - } - - return bridge(ctx); - } - - private Queue bridge(DefaultChannelHandlerContext ctx) { - Queue bridge = ctx.outBridge; - if (bridge == null) { - Queue newBridge = new ConcurrentLinkedQueue(); - if (OUT_BRIDGE_UPDATER.compareAndSet(ctx, null, newBridge)) { - bridge = newBridge; - } else { - bridge = ctx.outBridge; - } - } - return bridge; - } - } - @Override public ChannelPromise voidPromise() { return channel.voidPromise(); diff --git a/transport/src/main/java/io/netty/channel/DefaultChannelPipeline.java b/transport/src/main/java/io/netty/channel/DefaultChannelPipeline.java index 74eb88cf6e..410d815468 100755 --- a/transport/src/main/java/io/netty/channel/DefaultChannelPipeline.java +++ b/transport/src/main/java/io/netty/channel/DefaultChannelPipeline.java @@ -15,11 +15,7 @@ */ package io.netty.channel; -import io.netty.buffer.Buf; -import io.netty.buffer.BufUtil; -import io.netty.buffer.ByteBuf; -import io.netty.buffer.MessageBuf; -import io.netty.buffer.Unpooled; +import io.netty.buffer.ByteBufUtil; import io.netty.channel.Channel.Unsafe; import io.netty.util.concurrent.EventExecutor; import io.netty.util.concurrent.EventExecutorGroup; @@ -77,21 +73,10 @@ final class DefaultChannelPipeline implements ChannelPipeline { this.channel = channel; TailHandler tailHandler = new TailHandler(); - tail = new DefaultChannelHandlerContext(this, generateName(tailHandler), tailHandler); + tail = new DefaultChannelHandlerContext(this, null, generateName(tailHandler), tailHandler); - HeadHandler headHandler; - switch (channel.metadata().bufferType()) { - case BYTE: - headHandler = new ByteHeadHandler(channel.unsafe()); - break; - case MESSAGE: - headHandler = new MessageHeadHandler(channel.unsafe()); - break; - default: - throw new Error("unknown buffer type: " + channel.metadata().bufferType()); - } - - head = new DefaultChannelHandlerContext(this, generateName(headHandler), headHandler); + HeadHandler headHandler = new HeadHandler(channel.unsafe()); + head = new DefaultChannelHandlerContext(this, null, generateName(headHandler), headHandler); head.next = tail; tail.prev = head; @@ -331,14 +316,14 @@ final class DefaultChannelPipeline implements ChannelPipeline { synchronized (this) { if (!ctx.channel().isRegistered() || ctx.executor().inEventLoop()) { - remove0(ctx, true); + remove0(ctx); return ctx; } else { future = ctx.executor().submit(new Runnable() { @Override public void run() { synchronized (DefaultChannelPipeline.this) { - remove0(ctx, true); + remove0(ctx); } } }); @@ -354,14 +339,13 @@ final class DefaultChannelPipeline implements ChannelPipeline { return context; } - void remove0(DefaultChannelHandlerContext ctx, boolean forward) { + void remove0(DefaultChannelHandlerContext ctx) { DefaultChannelHandlerContext prev = ctx.prev; DefaultChannelHandlerContext next = ctx.next; prev.next = next; next.prev = prev; name2ctx.remove(ctx.name()); - - callHandlerRemoved(ctx, prev, next, forward); + callHandlerRemoved(ctx); } @Override @@ -458,11 +442,15 @@ final class DefaultChannelPipeline implements ChannelPipeline { } name2ctx.put(newName, newCtx); + // update the reference to the replacement so forward of buffered content will work correctly + oldCtx.prev = newCtx; + oldCtx.next = newCtx; + // Invoke newHandler.handlerAdded() first (i.e. before oldHandler.handlerRemoved() is invoked) // because callHandlerRemoved() will trigger inboundBufferUpdated() or flush() on newHandler and those // event handlers must be called after handlerAdded(). callHandlerAdded(newCtx); - callHandlerRemoved(oldCtx, newCtx, newCtx, true); + callHandlerRemoved(oldCtx); } private static void checkMultiplicity(ChannelHandlerContext ctx) { @@ -517,40 +505,23 @@ final class DefaultChannelPipeline implements ChannelPipeline { } } - private void callHandlerRemoved( - final DefaultChannelHandlerContext ctx, final DefaultChannelHandlerContext ctxPrev, - final DefaultChannelHandlerContext ctxNext, final boolean forward) { + private void callHandlerRemoved(final DefaultChannelHandlerContext ctx) { if (ctx.channel().isRegistered() && !ctx.executor().inEventLoop()) { ctx.executor().execute(new Runnable() { @Override public void run() { - callHandlerRemoved0(ctx, ctxPrev, ctxNext, forward); + callHandlerRemoved0(ctx); } }); return; } - callHandlerRemoved0(ctx, ctxPrev, ctxNext, forward); + callHandlerRemoved0(ctx); } - private void callHandlerRemoved0( - final DefaultChannelHandlerContext ctx, DefaultChannelHandlerContext ctxPrev, - DefaultChannelHandlerContext ctxNext, boolean forward) { - - final ChannelHandler handler = ctx.handler(); - - // Finish removal by forwarding buffer content and freeing the buffers. - if (forward) { - try { - ctx.forwardBufferContentAndFree(ctxPrev, ctxNext); - } catch (Throwable t) { - fireExceptionCaught(new ChannelPipelineException( - "failed to forward buffer content of " + ctx.handler().getClass().getName(), t)); - } - } - + private void callHandlerRemoved0(final DefaultChannelHandlerContext ctx) { // Notify the complete removal. try { - handler.handlerRemoved(ctx); + ctx.handler().handlerRemoved(ctx); } catch (Throwable t) { fireExceptionCaught(new ChannelPipelineException( ctx.handler().getClass().getName() + ".handlerRemoved() has thrown an exception.", t)); @@ -753,31 +724,8 @@ final class DefaultChannelPipeline implements ChannelPipeline { return buf.toString(); } - @Override - @SuppressWarnings("unchecked") - public MessageBuf inboundMessageBuffer() { - return (MessageBuf) head.nextInboundMessageBuffer(); - } - - @Override - public ByteBuf inboundByteBuffer() { - return head.nextInboundByteBuffer(); - } - - @Override - @SuppressWarnings("unchecked") - public MessageBuf outboundMessageBuffer() { - return (MessageBuf) tail.nextOutboundMessageBuffer(); - } - - @Override - public ByteBuf outboundByteBuffer() { - return tail.nextOutboundByteBuffer(); - } - @Override public ChannelPipeline fireChannelRegistered() { - head.initHeadHandler(); head.fireChannelRegistered(); return this; } @@ -795,7 +743,6 @@ final class DefaultChannelPipeline implements ChannelPipeline { @Override public ChannelPipeline fireChannelActive() { - head.initHeadHandler(); head.fireChannelActive(); if (channel.config().isAutoRead()) { @@ -828,8 +775,14 @@ final class DefaultChannelPipeline implements ChannelPipeline { } @Override - public ChannelPipeline fireInboundBufferUpdated() { - head.fireInboundBufferUpdated(); + public ChannelPipeline fireMessageReceived(Object msg) { + head.fireMessageReceived(msg); + return this; + } + + @Override + public ChannelPipeline fireMessageReceived(MessageList msgs) { + head.fireMessageReceived(msgs); return this; } @@ -842,6 +795,12 @@ final class DefaultChannelPipeline implements ChannelPipeline { return this; } + @Override + public ChannelPipeline fireChannelWritabilityChanged() { + head.fireChannelWritabilityChanged(); + return this; + } + @Override public ChannelFuture bind(SocketAddress localAddress) { return tail.bind(localAddress); @@ -873,13 +832,13 @@ final class DefaultChannelPipeline implements ChannelPipeline { } @Override - public ChannelFuture flush() { - return tail.flush(); + public ChannelFuture write(Object msg) { + return tail.write(msg); } @Override - public ChannelFuture write(Object message) { - return tail.write(message); + public ChannelFuture write(MessageList msgs) { + return tail.write(msgs); } @Override @@ -918,23 +877,13 @@ final class DefaultChannelPipeline implements ChannelPipeline { } @Override - public ChannelFuture flush(ChannelPromise promise) { - return tail.flush(promise); + public ChannelFuture write(Object msg, ChannelPromise promise) { + return tail.write(msg, promise); } @Override - public ChannelFuture sendFile(FileRegion region) { - return tail.sendFile(region); - } - - @Override - public ChannelFuture sendFile(FileRegion region, ChannelPromise promise) { - return tail.sendFile(region, promise); - } - - @Override - public ChannelFuture write(Object message, ChannelPromise promise) { - return tail.write(message, promise); + public ChannelFuture write(MessageList msgs, ChannelPromise promise) { + return tail.write(msgs, promise); } private void checkDuplicateName(String name) { @@ -973,9 +922,6 @@ final class DefaultChannelPipeline implements ChannelPipeline { // A special catch-all handler that handles both bytes and messages. static final class TailHandler implements ChannelInboundHandler { - final ByteBuf byteSink = Unpooled.buffer(0); - final MessageBuf msgSink = Unpooled.messageBuffer(0); - @Override public void channelRegistered(ChannelHandlerContext ctx) throws Exception { } @@ -991,6 +937,9 @@ final class DefaultChannelPipeline implements ChannelPipeline { @Override public void channelReadSuspended(ChannelHandlerContext ctx) throws Exception { } + @Override + public void channelWritabilityChanged(ChannelHandlerContext ctx) throws Exception { } + @Override public void handlerAdded(ChannelHandlerContext ctx) throws Exception { } @@ -1008,86 +957,54 @@ final class DefaultChannelPipeline implements ChannelPipeline { } @Override - public Buf newInboundBuffer(ChannelHandlerContext ctx) throws Exception { - throw new Error(); - } - - @Override - public void inboundBufferUpdated(ChannelHandlerContext ctx) throws Exception { - int byteSinkSize = byteSink.readableBytes(); - if (byteSinkSize != 0) { - byteSink.clear(); - logger.warn( - "Discarded {} inbound byte(s) that reached at the tail of the pipeline. " + - "Please check your pipeline configuration.", byteSinkSize); + public void messageReceived(ChannelHandlerContext ctx, MessageList msgs) throws Exception { + int length = msgs.size(); + if (length == 0) { + return; } - int msgSinkSize = msgSink.size(); - if (msgSinkSize != 0) { - MessageBuf in = msgSink; - for (;;) { - Object m = in.poll(); - if (m == null) { - break; - } - BufUtil.release(m); - logger.debug( - "Discarded inbound message {} that reached at the tail of the pipeline. " + - "Please check your pipeline configuration.", m); - } - logger.warn( - "Discarded {} inbound message(s) that reached at the tail of the pipeline. " + - "Please check your pipeline configuration.", msgSinkSize); + for (int i = 0; i < length; i ++) { + Object m = msgs.get(i); + logger.debug( + "Discarded inbound message {} that reached at the tail of the pipeline. " + + "Please check your pipeline configuration.", m); + + ByteBufUtil.release(m); } + + logger.warn( + "Discarded {} inbound message(s) that reached at the tail of the pipeline. " + + "Please check your pipeline configuration.", length); } } - abstract static class HeadHandler implements ChannelOutboundHandler { + static final class HeadHandler implements ChannelOutboundHandler { protected final Unsafe unsafe; - ByteBuf byteSink; - MessageBuf msgSink; - boolean initialized; protected HeadHandler(Unsafe unsafe) { this.unsafe = unsafe; } - void init(ChannelHandlerContext ctx) { - assert !initialized; - switch (ctx.channel().metadata().bufferType()) { - case BYTE: - byteSink = ctx.alloc().ioBuffer(); - msgSink = Unpooled.messageBuffer(0); - break; - case MESSAGE: - byteSink = Unpooled.buffer(0); - msgSink = Unpooled.messageBuffer(); - break; - default: - throw new Error(); - } - } - @Override - public final void handlerAdded(ChannelHandlerContext ctx) throws Exception { + public void handlerAdded(ChannelHandlerContext ctx) throws Exception { // NOOP } @Override - public final void handlerRemoved(ChannelHandlerContext ctx) throws Exception { + public void handlerRemoved(ChannelHandlerContext ctx) throws Exception { // NOOP } @Override - public final void bind( + public void bind( ChannelHandlerContext ctx, SocketAddress localAddress, ChannelPromise promise) throws Exception { unsafe.bind(localAddress, promise); } @Override - public final void connect( + public void connect( ChannelHandlerContext ctx, SocketAddress remoteAddress, SocketAddress localAddress, ChannelPromise promise) throws Exception { @@ -1095,34 +1012,29 @@ final class DefaultChannelPipeline implements ChannelPipeline { } @Override - public final void disconnect(ChannelHandlerContext ctx, ChannelPromise promise) throws Exception { + public void disconnect(ChannelHandlerContext ctx, ChannelPromise promise) throws Exception { unsafe.disconnect(promise); } @Override - public final void close(ChannelHandlerContext ctx, ChannelPromise promise) throws Exception { + public void close(ChannelHandlerContext ctx, ChannelPromise promise) throws Exception { unsafe.close(promise); } @Override - public final void deregister(ChannelHandlerContext ctx, ChannelPromise promise) throws Exception { + public void deregister(ChannelHandlerContext ctx, ChannelPromise promise) throws Exception { unsafe.deregister(promise); } @Override - public final void read(ChannelHandlerContext ctx) { + public void read(ChannelHandlerContext ctx) { unsafe.beginRead(); } @Override - public final void sendFile( - ChannelHandlerContext ctx, FileRegion region, ChannelPromise promise) throws Exception { - unsafe.sendFile(region, promise); - } - - @Override - public final Buf newOutboundBuffer(ChannelHandlerContext ctx) throws Exception { - throw new Error(); + public void write( + ChannelHandlerContext ctx, MessageList msgs, ChannelPromise promise) throws Exception { + unsafe.write(msgs, promise); } @Override @@ -1130,62 +1042,4 @@ final class DefaultChannelPipeline implements ChannelPipeline { ctx.fireExceptionCaught(cause); } } - - private static final class ByteHeadHandler extends HeadHandler { - - private ByteHeadHandler(Unsafe unsafe) { - super(unsafe); - } - - @Override - public void flush(ChannelHandlerContext ctx, ChannelPromise promise) throws Exception { - int discardedMessages = 0; - MessageBuf in = msgSink; - for (;;) { - Object m = in.poll(); - if (m == null) { - break; - } - - if (m instanceof ByteBuf) { - ByteBuf src = (ByteBuf) m; - byteSink.writeBytes(src, src.readerIndex(), src.readableBytes()); - } else { - logger.debug( - "Discarded outbound message {} that reached at the head of the pipeline. " + - "Please check your pipeline configuration.", m); - discardedMessages ++; - } - - BufUtil.release(m); - } - - if (discardedMessages != 0) { - logger.warn( - "Discarded {} outbound message(s) that reached at the head of the pipeline. " + - "Please check your pipeline configuration.", discardedMessages); - } - - unsafe.flush(promise); - } - } - - private static final class MessageHeadHandler extends HeadHandler { - - private MessageHeadHandler(Unsafe unsafe) { - super(unsafe); - } - - @Override - public void flush(ChannelHandlerContext ctx, ChannelPromise promise) throws Exception { - int byteSinkSize = byteSink.readableBytes(); - if (byteSinkSize != 0) { - byteSink.clear(); - logger.warn( - "Discarded {} outbound byte(s) that reached at the head of the pipeline. " + - "Please check your pipeline configuration.", byteSinkSize); - } - unsafe.flush(promise); - } - } } diff --git a/transport/src/main/java/io/netty/channel/DefaultFileRegion.java b/transport/src/main/java/io/netty/channel/DefaultFileRegion.java index dbc84db428..c0a20cf154 100644 --- a/transport/src/main/java/io/netty/channel/DefaultFileRegion.java +++ b/transport/src/main/java/io/netty/channel/DefaultFileRegion.java @@ -33,6 +33,7 @@ public class DefaultFileRegion extends AbstractReferenceCounted implements FileR private final FileChannel file; private final long position; private final long count; + private long transfered; /** * Create a new instance @@ -66,6 +67,11 @@ public class DefaultFileRegion extends AbstractReferenceCounted implements FileR return count; } + @Override + public long transfered() { + return transfered; + } + @Override public long transferTo(WritableByteChannel target, long position) throws IOException { long count = this.count - position; @@ -78,7 +84,11 @@ public class DefaultFileRegion extends AbstractReferenceCounted implements FileR return 0L; } - return file.transferTo(this.position + position, count, target); + long written = file.transferTo(this.position + position, count, target); + if (written > 0) { + transfered += written; + } + return written; } @Override diff --git a/transport/src/main/java/io/netty/channel/FileRegion.java b/transport/src/main/java/io/netty/channel/FileRegion.java index 5201939cbe..a643398012 100644 --- a/transport/src/main/java/io/netty/channel/FileRegion.java +++ b/transport/src/main/java/io/netty/channel/FileRegion.java @@ -59,6 +59,11 @@ public interface FileRegion extends ReferenceCounted { */ long position(); + /** + * Return the bytes which was transfered already + */ + long transfered(); + /** * Returns the number of bytes to transfer. */ diff --git a/transport/src/main/java/io/netty/channel/FixedRecvByteBufAllocator.java b/transport/src/main/java/io/netty/channel/FixedRecvByteBufAllocator.java new file mode 100644 index 0000000000..b4087bae66 --- /dev/null +++ b/transport/src/main/java/io/netty/channel/FixedRecvByteBufAllocator.java @@ -0,0 +1,69 @@ +/* + * Copyright 2012 The Netty Project + * + * The Netty Project licenses this file to you under the Apache License, + * version 2.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +package io.netty.channel; + +import io.netty.buffer.ByteBuf; +import io.netty.buffer.ByteBufAllocator; + + +/** + * The {@link RecvByteBufAllocator} that always yields the same buffer + * size prediction. This predictor ignores the feed back from the I/O thread. + */ +public class FixedRecvByteBufAllocator implements RecvByteBufAllocator { + + private static final class HandleImpl implements Handle { + + private final int bufferSize; + + HandleImpl(int bufferSize) { + this.bufferSize = bufferSize; + } + + @Override + public ByteBuf allocate(ByteBufAllocator alloc) { + return alloc.ioBuffer(bufferSize); + } + + @Override + public int guess() { + return bufferSize; + } + + @Override + public void record(int actualReadBytes) { } + } + + private final Handle handle; + + /** + * Creates a new predictor that always returns the same prediction of + * the specified buffer size. + */ + public FixedRecvByteBufAllocator(int bufferSize) { + if (bufferSize <= 0) { + throw new IllegalArgumentException( + "bufferSize must greater than 0: " + bufferSize); + } + + handle = new HandleImpl(bufferSize); + } + + @Override + public Handle newHandle() { + return handle; + } +} diff --git a/transport/src/main/java/io/netty/channel/MessageList.java b/transport/src/main/java/io/netty/channel/MessageList.java new file mode 100644 index 0000000000..50023b2546 --- /dev/null +++ b/transport/src/main/java/io/netty/channel/MessageList.java @@ -0,0 +1,475 @@ +/* + * Copyright 2013 The Netty Project + * + * The Netty Project licenses this file to you under the Apache License, + * version 2.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ + +package io.netty.channel; + +import io.netty.buffer.ByteBufUtil; +import io.netty.util.Recycler; +import io.netty.util.Recycler.Handle; +import io.netty.util.Signal; +import io.netty.util.internal.PlatformDependent; + +import java.util.Arrays; + +public final class MessageList { + + private static final int DEFAULT_INITIAL_CAPACITY = 8; + private static final int MIN_INITIAL_CAPACITY = 4; + + private static final Recycler> RECYCLER = new Recycler>() { + @Override + protected MessageList newObject(Handle handle) { + return new MessageList(handle); + } + }; + + public static MessageList newInstance() { + return newInstance(DEFAULT_INITIAL_CAPACITY); + } + + @SuppressWarnings("unchecked") + public static MessageList newInstance(int minCapacity) { + MessageList ret = (MessageList) RECYCLER.get(); + ret.ensureCapacity(minCapacity); + return ret; + } + + public static MessageList newInstance(T value) { + MessageList ret = newInstance(MIN_INITIAL_CAPACITY); + ret.add(value); + return ret; + } + + public MessageList retainAll() { + int size = this.size; + for (int i = 0; i < size; i ++) { + ByteBufUtil.retain(elements[i]); + } + return this; + } + + public MessageList retainAll(int increment) { + int size = this.size; + for (int i = 0; i < size; i ++) { + ByteBufUtil.retain(elements[i], increment); + } + return this; + } + + public boolean releaseAll() { + boolean releasedAll = true; + int size = this.size; + for (int i = 0; i < size; i++) { + releasedAll &= ByteBufUtil.release(elements[i]); + } + return releasedAll; + } + + public boolean releaseAll(int decrement) { + boolean releasedAll = true; + int size = this.size; + for (int i = 0; i < size; i++) { + releasedAll &= ByteBufUtil.release(elements[i], decrement); + } + return releasedAll; + } + + public boolean releaseAllAndRecycle() { + return releaseAll() && recycle(); + } + + public boolean releaseAllAndRecycle(int decrement) { + return releaseAll(decrement) && recycle(); + } + + public boolean recycle() { + clear(); + return RECYCLER.recycle(this, handle); + } + + private final Handle handle; + private T[] elements; + private int size; + + MessageList(Handle handle) { + this(handle, DEFAULT_INITIAL_CAPACITY); + } + + MessageList(Handle handle, int initialCapacity) { + this.handle = handle; + initialCapacity = normalizeCapacity(initialCapacity); + elements = newArray(initialCapacity); + } + + private MessageList(Handle handle, T[] elements, int size) { + this.handle = handle; + this.elements = elements; + this.size = size; + } + + public int size() { + return size; + } + + public int capacity() { + return elements.length; + } + + public boolean isEmpty() { + return size == 0; + } + + public T get(int index) { + checkExclusive(index); + return elements[index]; + } + + public MessageList set(int index, T value) { + checkExclusive(index); + if (value == null) { + throw new NullPointerException("value"); + } + elements[index] = value; + return this; + } + + public MessageList set(int index, T[] src) { + if (src == null) { + throw new NullPointerException("src"); + } + set(index, src, 0, src.length); + return this; + } + + public MessageList set(int index, T[] src, int srcIdx, int srcLen) { + checkElements(src, srcIdx, srcLen); + + if (srcLen == 0) { + return remove(index); + } + + if (srcLen == 1) { + return set(index, src[srcIdx]); + } + + checkExclusive(index); + + int oldSize = size; + int newSize = oldSize + srcLen - 1; + ensureCapacity(newSize); + System.arraycopy(elements, index + 1, elements, index + srcLen, oldSize - (index + 1)); + System.arraycopy(src, srcIdx, elements, index, srcLen); + size = newSize; + return this; + } + + public MessageList set(int index, int length, T value) { + if (length == 0) { + return add(index, value); + } + + if (length == 1) { + return set(index, value); + } + + checkRange(index, length); + if (value == null) { + throw new NullPointerException("value"); + } + + elements[index] = value; + int nextElemIdx = index + length; + int oldSize = size; + int newSize = oldSize - length + 1; + System.arraycopy(elements, nextElemIdx, elements, index + 1, oldSize - nextElemIdx); + Arrays.fill(elements, newSize, oldSize, null); + size = newSize; + return this; + } + + public MessageList set(int index, int length, T[] src) { + if (src == null) { + throw new NullPointerException("src"); + } + return set(index, length, src, 0, src.length); + } + + public MessageList set(int index, int length, T[] src, int srcIdx, int srcLen) { + if (length == 0) { + return add(index, src, srcIdx, srcLen); + } + + if (length == 1) { + return set(index, src, srcIdx, srcLen); + } + + checkRange(index, length); + checkElements(src, srcIdx, srcLen); + + if (srcLen == length) { + System.arraycopy(src, srcIdx, elements, index, length); + } else if (srcLen < length) { + int remainderIdx = index + length; + int oldSize = size; + int newSize = oldSize - (length - srcLen); + System.arraycopy(src, srcIdx, elements, index, srcLen); + System.arraycopy(elements, remainderIdx, elements, index + srcLen, oldSize - remainderIdx); + Arrays.fill(elements, newSize, oldSize, null); + size = newSize; + } else { + int remainderIdx = index + length; + int oldSize = size; + int newSize = oldSize + srcLen - length; + ensureCapacity(newSize); + // 0 [1 2] 3 4 5 -> 0 [1 2 3] 3 4 5 + System.arraycopy(elements, remainderIdx, elements, index + srcLen, oldSize - remainderIdx); + System.arraycopy(src, srcIdx, elements, index, srcLen); + size = newSize; + } + return this; + } + + public MessageList add(T value) { + if (value == null) { + throw new NullPointerException("value"); + } + int oldSize = size; + int newSize = oldSize + 1; + ensureCapacity(newSize); + elements[oldSize] = value; + size = newSize; + return this; + } + + public MessageList add(T[] src) { + if (src == null) { + throw new NullPointerException("src"); + } + return add(src, 0, src.length); + } + + public MessageList add(T[] src, int srcIdx, int srcLen) { + checkElements(src, srcIdx, srcLen); + + int oldSize = size; + int newSize = oldSize + srcLen; + ensureCapacity(newSize); + System.arraycopy(src, srcIdx, elements, oldSize, srcLen); + size = newSize; + return this; + } + + public MessageList add(int index, T value) { + checkInclusive(index); + + if (value == null) { + throw new NullPointerException("value"); + } + + int oldSize = size; + int newSize = oldSize + 1; + ensureCapacity(newSize); + System.arraycopy(elements, index, elements, index + 1, oldSize - index); + elements[index] = value; + size = newSize; + return this; + } + + public MessageList add(int index, T[] src) { + if (src == null) { + throw new NullPointerException("src"); + } + return add(index, src, 0, src.length); + } + + public MessageList add(int index, T[] src, int srcIdx, int srcLen) { + checkInclusive(index); + checkElements(src, srcIdx, srcLen); + + if (srcLen == 0) { + return this; + } + + int oldSize = size; + int newSize = oldSize + srcLen; + ensureCapacity(newSize); + System.arraycopy(elements, index, elements, index + srcLen, oldSize - index); + System.arraycopy(src, srcIdx, elements, index, srcLen); + size = newSize; + return this; + } + + public MessageList remove(int index) { + checkExclusive(index); + int oldSize = size; + int newSize = oldSize - 1; + System.arraycopy(elements, index + 1, elements, index, newSize - index); + elements[newSize] = null; + size = newSize; + return this; + } + + public MessageList remove(int index, int length) { + checkRange(index, length); + if (length == 0) { + return this; + } + + int oldSize = size; + int newSize = oldSize - length; + System.arraycopy(elements, index + length, elements, index, newSize - index); + Arrays.fill(elements, newSize, oldSize, null); + size = newSize; + return this; + } + + public MessageList clear() { + Arrays.fill(elements, 0, size, null); + size = 0; + return this; + } + + public MessageList copy() { + return new MessageList(handle, elements.clone(), size); + } + + public MessageList copy(int index, int length) { + checkRange(index, length); + MessageList copy = new MessageList(handle, length); + System.arraycopy(elements, index, copy.elements, 0, length); + copy.size = length; + return copy; + } + + @SuppressWarnings("unchecked") + public MessageList cast() { + return (MessageList) this; + } + + public T[] array() { + return elements; + } + + public boolean forEach(MessageListProcessor proc) { + if (proc == null) { + throw new NullPointerException("proc"); + } + + @SuppressWarnings("unchecked") + MessageListProcessor p = (MessageListProcessor) proc; + + int size = this.size; + try { + for (int i = 0; i < size; i ++) { + i += p.process(this, i, elements[i]); + } + } catch (Signal abort) { + abort.expect(MessageListProcessor.ABORT); + return false; + } catch (Exception e) { + PlatformDependent.throwException(e); + } + + return true; + } + + public boolean forEach(int index, int length, MessageListProcessor proc) { + checkRange(index, length); + if (proc == null) { + throw new NullPointerException("proc"); + } + + @SuppressWarnings("unchecked") + MessageListProcessor p = (MessageListProcessor) proc; + + int end = index + length; + try { + for (int i = index; i < end;) { + i += p.process(this, i, elements[i]); + } + } catch (Signal abort) { + abort.expect(MessageListProcessor.ABORT); + return false; + } catch (Exception e) { + PlatformDependent.throwException(e); + } + + return true; + } + + private void ensureCapacity(int capacity) { + if (elements.length >= capacity) { + return; + } + + T[] newElements = newArray(normalizeCapacity(capacity)); + System.arraycopy(elements, 0, newElements, 0, size); + elements = newElements; + } + + private static int normalizeCapacity(int initialCapacity) { + if (initialCapacity <= MIN_INITIAL_CAPACITY) { + initialCapacity = MIN_INITIAL_CAPACITY; + } else { + initialCapacity |= initialCapacity >>> 1; + initialCapacity |= initialCapacity >>> 2; + initialCapacity |= initialCapacity >>> 4; + initialCapacity |= initialCapacity >>> 8; + initialCapacity |= initialCapacity >>> 16; + initialCapacity ++; + + if (initialCapacity < 0) { + initialCapacity >>>= 1; + } + } + return initialCapacity; + } + + @SuppressWarnings({ "unchecked", "SuspiciousArrayCast" }) + private T[] newArray(int initialCapacity) { + return (T[]) new Object[initialCapacity]; + } + + private void checkExclusive(int index) { + if (index >= size) { + throw new IndexOutOfBoundsException(String.valueOf(index)); + } + } + + private void checkInclusive(int index) { + if (index > size) { + throw new IndexOutOfBoundsException(String.valueOf(index)); + } + } + + private void checkRange(int index, int length) { + if (index + length > size) { + throw new IndexOutOfBoundsException("index: " + index + ", length: " + length + ", size: " + size); + } + } + + private void checkElements(T[] src, int srcIdx, int srcLen) { + if (src == null) { + throw new NullPointerException("src"); + } + int end = srcIdx + srcLen; + for (int i = srcIdx; i < end; i ++) { + if (src[i] == null) { + throw new NullPointerException("src[" + i + ']'); + } + } + } +} diff --git a/buffer/src/main/java/io/netty/buffer/BufType.java b/transport/src/main/java/io/netty/channel/MessageListProcessor.java similarity index 51% rename from buffer/src/main/java/io/netty/buffer/BufType.java rename to transport/src/main/java/io/netty/channel/MessageListProcessor.java index 8b9ffd0674..37cd20d87a 100644 --- a/buffer/src/main/java/io/netty/buffer/BufType.java +++ b/transport/src/main/java/io/netty/channel/MessageListProcessor.java @@ -1,5 +1,5 @@ /* - * Copyright 2012 The Netty Project + * Copyright 2013 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance @@ -13,19 +13,19 @@ * License for the specific language governing permissions and limitations * under the License. */ -package io.netty.buffer; -/** - * The type of the Buf - */ -public enum BufType { - /** - * Operates on bytes. - */ - BYTE, +package io.netty.channel; + +import io.netty.util.Signal; + +public interface MessageListProcessor { + + Signal ABORT = new Signal(MessageListProcessor.class.getName() + ".ABORT"); /** - * Operates on messages, which can be of any kind. + * @return the number of elements processed. {@link MessageList#forEach(MessageListProcessor)} will determine + * the index of the next element to be processed based on this value. Usually, an implementation will + * return {@code 1} to advance the index by {@code 1}. */ - MESSAGE + int process(MessageList messages, int index, T value) throws Exception; } diff --git a/transport/src/main/java/io/netty/channel/RecvByteBufAllocator.java b/transport/src/main/java/io/netty/channel/RecvByteBufAllocator.java new file mode 100644 index 0000000000..371207a9f0 --- /dev/null +++ b/transport/src/main/java/io/netty/channel/RecvByteBufAllocator.java @@ -0,0 +1,54 @@ +/* + * Copyright 2012 The Netty Project + * + * The Netty Project licenses this file to you under the Apache License, + * version 2.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +package io.netty.channel; + +import io.netty.buffer.ByteBuf; +import io.netty.buffer.ByteBufAllocator; + +/** + * Allocates a new receive buffer whose capacity is probably large enough to read all inbound data and small enough + * not to waste its space. + */ +public interface RecvByteBufAllocator { + + /** + * Creates a new handle. The handle provides the actual operations and keeps the internal information which is + * required for predicting an optimal buffer capacity. + */ + Handle newHandle(); + + public interface Handle { + /** + * Creates a new receive buffer whose capacity is probably large enough to read all inbound data and small + * enough not to waste its space. + */ + ByteBuf allocate(ByteBufAllocator alloc); + + /** + * Similar to {@link #allocate(ByteBufAllocator)} except that it does not allocate anything but just tells the + * capacity. + */ + int guess(); + + /** + * Records the the actual number of read bytes in the previous read operation so that the allocator allocates + * the buffer with potentially more correct capacity. + * + * @param actualReadBytes the actual number of read bytes in the previous read operation + */ + void record(int actualReadBytes); + } +} diff --git a/transport/src/main/java/io/netty/channel/SimpleChannelInboundHandler.java b/transport/src/main/java/io/netty/channel/SimpleChannelInboundHandler.java new file mode 100644 index 0000000000..e667f6fc13 --- /dev/null +++ b/transport/src/main/java/io/netty/channel/SimpleChannelInboundHandler.java @@ -0,0 +1,89 @@ +/* + * Copyright 2013 The Netty Project + * + * The Netty Project licenses this file to you under the Apache License, + * version 2.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +package io.netty.channel; + +import io.netty.util.internal.TypeParameterMatcher; + +/** + * {@link ChannelInboundHandlerAdapter} which allows to explicit only handle a specific type of messages. + * + * For example here is an implementation which only handle {@link String} messages. + * + *
+ *     public class StringHandler extends
+ *             {@link SimpleChannelInboundHandler}<{@link String}> {
+ *
+ *         {@code @Override}
+ *         public void messageReceived({@link ChannelHandlerContext} ctx, {@link String} message)
+ *                 throws {@link Exception} {
+ *             System.out.println(message);
+ *         }
+ *     }
+ * 
+ * + */ +public abstract class SimpleChannelInboundHandler extends ChannelInboundHandlerAdapter { + + private final TypeParameterMatcher matcher; + + protected SimpleChannelInboundHandler() { + matcher = TypeParameterMatcher.find(this, SimpleChannelInboundHandler.class, "I"); + } + + protected SimpleChannelInboundHandler(Class inboundMessageType) { + matcher = TypeParameterMatcher.get(inboundMessageType); + } + + public boolean acceptInboundMessage(Object msg) throws Exception { + return matcher.match(msg); + } + + @Override + public void messageReceived(ChannelHandlerContext ctx, MessageList msgs) throws Exception { + MessageList unaccepted = MessageList.newInstance(); + int size = msgs.size(); + try { + for (int i = 0; i < size; i++) { + Object msg = msgs.get(i); + if (acceptInboundMessage(msg)) { + if (!unaccepted.isEmpty()) { + ctx.fireMessageReceived(unaccepted); + unaccepted = MessageList.newInstance(); + } + + @SuppressWarnings("unchecked") + I imsg = (I) msg; + messageReceived(ctx, imsg); + } else { + unaccepted.add(msg); + } + } + } finally { + msgs.recycle(); + ctx.fireMessageReceived(unaccepted); + } + } + + /** + * Is called for each message of type {@link I}. + * + * @param ctx the {@link ChannelHandlerContext} which this {@link SimpleChannelInboundHandler} + * belongs to + * @param msg the message to handle + * @throws Exception is thrown if an error accour + */ + protected abstract void messageReceived(ChannelHandlerContext ctx, I msg) throws Exception; +} diff --git a/transport/src/main/java/io/netty/channel/aio/AioCompletionHandler.java b/transport/src/main/java/io/netty/channel/aio/AioCompletionHandler.java index ceaa84eecc..47f42d3e61 100644 --- a/transport/src/main/java/io/netty/channel/aio/AioCompletionHandler.java +++ b/transport/src/main/java/io/netty/channel/aio/AioCompletionHandler.java @@ -23,17 +23,23 @@ import java.nio.channels.CompletionHandler; /** * Special {@link CompletionHandler} which makes sure that the callback methods gets executed in the {@link EventLoop} */ -public abstract class AioCompletionHandler implements CompletionHandler { +public abstract class AioCompletionHandler implements CompletionHandler { + + private final C channel; + + protected AioCompletionHandler(C channel) { + this.channel = channel; + } /** * See {@link CompletionHandler#completed(Object, Object)} */ - protected abstract void completed0(V result, A channel); + protected abstract void completed0(C channel, V result, A attachment); /** * Set {@link CompletionHandler#failed(Throwable, Object)} */ - protected abstract void failed0(Throwable exc, A channel); + protected abstract void failed0(C channel, Throwable exc, A attachment); // According to JDK AIO documentation, the ExecutorService a user specified must not call the Runnable given by // JDK AIO implementation directly. However, we violates that rull by calling Runnable.run() directly for @@ -49,14 +55,14 @@ public abstract class AioCompletionHandler implements Comp }; @Override - public final void completed(final V result, final A channel) { + public final void completed(final V result, final A attachment) { EventLoop loop = channel.eventLoop(); if (loop.inEventLoop()) { Integer d = STACK_DEPTH.get(); if (d < MAX_STACK_DEPTH) { STACK_DEPTH.set(d + 1); try { - completed0(result, channel); + completed0(channel, result, attachment); } finally { STACK_DEPTH.set(d); } @@ -66,7 +72,7 @@ public abstract class AioCompletionHandler implements Comp loop.execute(new AioEventLoop.RecursionBreakingRunnable() { @Override public void run() { - completed0(result, channel); + completed0(channel, result, attachment); } }); } @@ -74,21 +80,21 @@ public abstract class AioCompletionHandler implements Comp loop.execute(new Runnable() { @Override public void run() { - completed0(result, channel); + completed0(channel, result, attachment); } }); } } @Override - public final void failed(final Throwable exc, final A channel) { + public final void failed(final Throwable exc, final A attachment) { EventLoop loop = channel.eventLoop(); if (loop.inEventLoop()) { Integer d = STACK_DEPTH.get(); if (d < MAX_STACK_DEPTH) { STACK_DEPTH.set(d + 1); try { - failed0(exc, channel); + failed0(channel, exc, attachment); } finally { STACK_DEPTH.set(d); } @@ -98,7 +104,7 @@ public abstract class AioCompletionHandler implements Comp loop.execute(new AioEventLoop.RecursionBreakingRunnable() { @Override public void run() { - failed0(exc, channel); + failed0(channel, exc, attachment); } }); } @@ -106,7 +112,7 @@ public abstract class AioCompletionHandler implements Comp loop.execute(new Runnable() { @Override public void run() { - failed0(exc, channel); + failed0(channel, exc, attachment); } }); } diff --git a/transport/src/main/java/io/netty/channel/aio/AioEventLoop.java b/transport/src/main/java/io/netty/channel/aio/AioEventLoop.java index 05dd153ab6..e72ddfae82 100644 --- a/transport/src/main/java/io/netty/channel/aio/AioEventLoop.java +++ b/transport/src/main/java/io/netty/channel/aio/AioEventLoop.java @@ -110,10 +110,11 @@ final class AioEventLoop extends SingleThreadEventLoop { @Override protected void addTask(Runnable task) { + if (task == null) { + throw new NullPointerException("task"); + } + if (task instanceof RecursionBreakingRunnable) { - if (task == null) { - throw new NullPointerException("task"); - } if (isTerminated()) { reject(); } diff --git a/transport/src/main/java/io/netty/channel/embedded/EmbeddedByteChannel.java b/transport/src/main/java/io/netty/channel/embedded/EmbeddedByteChannel.java deleted file mode 100644 index 421a3b30ca..0000000000 --- a/transport/src/main/java/io/netty/channel/embedded/EmbeddedByteChannel.java +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright 2012 The Netty Project - * - * The Netty Project licenses this file to you under the Apache License, - * version 2.0 (the "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. - */ -package io.netty.channel.embedded; - -import io.netty.buffer.BufType; -import io.netty.buffer.ByteBuf; -import io.netty.buffer.Unpooled; -import io.netty.channel.Channel; -import io.netty.channel.ChannelHandler; -import io.netty.channel.ChannelMetadata; -import io.netty.channel.ChannelPipeline; - - -/** - * Embedded {@link Channel} which operates on bytes - */ -public class EmbeddedByteChannel extends AbstractEmbeddedChannel { - - private static final ChannelMetadata METADATA = new ChannelMetadata(BufType.BYTE, false); - - /** - * Create a new instance with the given {@link ChannelHandler}s in the {@link ChannelPipeline} - */ - public EmbeddedByteChannel(ChannelHandler... handlers) { - super(Unpooled.buffer(), handlers); - } - - @Override - public ChannelMetadata metadata() { - return METADATA; - } - - @Override - public ByteBuf inboundBuffer() { - return pipeline().inboundByteBuffer(); - } - - @Override - public ByteBuf lastOutboundBuffer() { - return (ByteBuf) lastOutboundBuffer; - } - - @Override - public ByteBuf readOutbound() { - if (!lastOutboundBuffer().isReadable()) { - return null; - } - try { - return lastOutboundBuffer().readBytes(lastOutboundBuffer().readableBytes()); - } finally { - lastOutboundBuffer().clear(); - } - } - - @Override - protected void writeInbound0(ByteBuf data) { - inboundBuffer().writeBytes(data); - } - - @Override - protected boolean hasReadableOutboundBuffer() { - return lastOutboundBuffer().isReadable(); - } - - @Override - protected void doFlushByteBuffer(ByteBuf buf) throws Exception { - lastOutboundBuffer().writeBytes(buf); - } -} diff --git a/transport/src/main/java/io/netty/channel/embedded/AbstractEmbeddedChannel.java b/transport/src/main/java/io/netty/channel/embedded/EmbeddedChannel.java similarity index 55% rename from transport/src/main/java/io/netty/channel/embedded/AbstractEmbeddedChannel.java rename to transport/src/main/java/io/netty/channel/embedded/EmbeddedChannel.java index f950809652..54862aea62 100755 --- a/transport/src/main/java/io/netty/channel/embedded/AbstractEmbeddedChannel.java +++ b/transport/src/main/java/io/netty/channel/embedded/EmbeddedChannel.java @@ -15,92 +15,81 @@ */ package io.netty.channel.embedded; -import io.netty.buffer.Buf; -import io.netty.buffer.ByteBuf; -import io.netty.buffer.MessageBuf; -import io.netty.buffer.Unpooled; import io.netty.channel.AbstractChannel; import io.netty.channel.Channel; import io.netty.channel.ChannelConfig; import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelHandler; import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.ChannelInboundByteHandler; -import io.netty.channel.ChannelInboundMessageHandler; +import io.netty.channel.ChannelInboundHandlerAdapter; +import io.netty.channel.ChannelMetadata; import io.netty.channel.ChannelPipeline; import io.netty.channel.ChannelPromise; -import io.netty.channel.ChannelStateHandlerAdapter; import io.netty.channel.DefaultChannelConfig; import io.netty.channel.EventLoop; +import io.netty.channel.MessageList; import io.netty.util.internal.PlatformDependent; import io.netty.util.internal.logging.InternalLogger; import io.netty.util.internal.logging.InternalLoggerFactory; import java.net.SocketAddress; import java.nio.channels.ClosedChannelException; +import java.util.ArrayDeque; +import java.util.Queue; /** * Base class for {@link Channel} implementations that are used in an embedded fashion. - * - * @param the type of data that can be written to this {@link Channel} */ -public abstract class AbstractEmbeddedChannel extends AbstractChannel { +public class EmbeddedChannel extends AbstractChannel { - private static final InternalLogger logger = InternalLoggerFactory.getInstance(AbstractEmbeddedChannel.class); + private static final InternalLogger logger = InternalLoggerFactory.getInstance(EmbeddedChannel.class); + + private static final ChannelMetadata METADATA = new ChannelMetadata(false); private final EmbeddedEventLoop loop = new EmbeddedEventLoop(); private final ChannelConfig config = new DefaultChannelConfig(this); private final SocketAddress localAddress = new EmbeddedSocketAddress(); private final SocketAddress remoteAddress = new EmbeddedSocketAddress(); - private final MessageBuf lastInboundMessageBuffer = Unpooled.messageBuffer().retain(2); - private final ByteBuf lastInboundByteBuffer = Unpooled.buffer().retain(2); - protected final Object lastOutboundBuffer; + private final Queue lastInboundBuffer = new ArrayDeque(); + private final Queue lastOutboundBuffer = new ArrayDeque(); private Throwable lastException; private int state; // 0 = OPEN, 1 = ACTIVE, 2 = CLOSED /** * Create a new instance * - * @param lastOutboundBuffer the last outbound buffer which will hold all the written data - * @param handlers the @link ChannelHandler}s which will be add in the {@link ChannelPipeline} + * @param handlers the @link ChannelHandler}s which will be add in the {@link ChannelPipeline} */ - AbstractEmbeddedChannel(Object lastOutboundBuffer, ChannelHandler... handlers) { + public EmbeddedChannel(ChannelHandler... handlers) { super(null, null); if (handlers == null) { throw new NullPointerException("handlers"); } - this.lastOutboundBuffer = lastOutboundBuffer; - int nHandlers = 0; - boolean hasBuffer = false; ChannelPipeline p = pipeline(); for (ChannelHandler h: handlers) { if (h == null) { break; } nHandlers ++; - ChannelHandlerContext ctx = p.addLast(h).context(h); - - if (ctx.hasInboundByteBuffer() || ctx.hasOutboundByteBuffer() - || ctx.hasInboundMessageBuffer() || ctx.hasOutboundMessageBuffer()) { - hasBuffer = true; - } + p.addLast(h); } if (nHandlers == 0) { throw new IllegalArgumentException("handlers is empty."); } - if (!hasBuffer) { - throw new IllegalArgumentException("handlers does not provide any buffers."); - } - - p.addLast(new LastInboundMessageHandler(), new LastInboundByteHandler()); + p.addLast(new LastInboundHandler()); loop.register(this); } + @Override + public ChannelMetadata metadata() { + return METADATA; + } + @Override public ChannelConfig config() { return config; @@ -117,33 +106,87 @@ public abstract class AbstractEmbeddedChannel extends AbstractChannel { } /** - * Return the last inbound {@link MessageBuf} which will hold all the {@link Object}s that where received - * by this {@link Channel} + * Returns the buffer which holds all the {@link Object}s that were received by this {@link Channel}. */ - public MessageBuf lastInboundMessageBuffer() { - return lastInboundMessageBuffer; + public Queue lastInboundBuffer() { + return lastInboundBuffer; } /** - * Return the last inbound {@link ByteBuf} which will hold all the bytes that where received - * by this {@link Channel} + * Returns the buffer which holds all the {@link Object}s that were written by this {@link Channel}. */ - public ByteBuf lastInboundByteBuffer() { - return lastInboundByteBuffer; + public Queue lastOutboundBuffer() { + return lastOutboundBuffer; } /** * Return received data from this {@link Channel} */ public Object readInbound() { - if (lastInboundByteBuffer.isReadable()) { - try { - return lastInboundByteBuffer.readBytes(lastInboundByteBuffer.readableBytes()); - } finally { - lastInboundByteBuffer.clear(); - } + return lastInboundBuffer.poll(); + } + + /** + * Read data froum the outbound. This may return {@code null} if nothing is readable. + */ + public Object readOutbound() { + return lastOutboundBuffer.poll(); + } + + /** + * Write messages to the inbound of this {@link Channel}. + * + * @param msgs the messages to be written + * + * @return {@code true} if the write operation did add something to the the inbound buffer + */ + public boolean writeInbound(Object... msgs) { + ensureOpen(); + if (msgs.length == 0) { + return !lastInboundBuffer.isEmpty(); } - return lastInboundMessageBuffer.poll(); + MessageList list = MessageList.newInstance(msgs.length); + list.add(msgs); + pipeline().fireMessageReceived(list); + runPendingTasks(); + checkException(); + return !lastInboundBuffer.isEmpty(); + } + + /** + * Write messages to the outbound of this {@link Channel}. + * + * @param msgs the messages to be written + * @return bufferReadable returns {@code true} if the write operation did add something to the the outbound buffer + */ + public boolean writeOutbound(Object... msgs) { + ensureOpen(); + if (msgs.length == 0) { + return !lastOutboundBuffer.isEmpty(); + } + MessageList list = MessageList.newInstance(msgs.length); + list.add(msgs); + ChannelFuture future = write(list); + assert future.isDone(); + if (future.cause() != null) { + recordException(future.cause()); + } + runPendingTasks(); + checkException(); + return !lastOutboundBuffer.isEmpty(); + } + + /** + * Mark this {@link Channel} as finished. Any futher try to write data to it will fail. + * + * + * @return bufferReadable returns {@code true} if any of the used buffers has something left to read + */ + public boolean finish() { + close(); + runPendingTasks(); + checkException(); + return !lastInboundBuffer.isEmpty() || !lastOutboundBuffer.isEmpty(); } /** @@ -244,120 +287,34 @@ public abstract class AbstractEmbeddedChannel extends AbstractChannel { return false; } - /** - * Read data froum the outbound. This may return {@code null} if nothing is readable. - */ - public abstract O readOutbound(); - - /** - * Return the inbound buffer in which inbound messages are stored. - */ - public abstract Buf inboundBuffer(); - - /** - * Return the last outbound buffer in which all the written outbound messages are stored. - */ - public abstract Buf lastOutboundBuffer(); - - /** - * Mark this {@link Channel} as finished. Any futher try to write data to it will fail. - * - * - * @return bufferReadable returns {@code true} if any of the used buffers has something left to read - */ - public boolean finish() { - close(); - runPendingTasks(); - checkException(); - return lastInboundByteBuffer().isReadable() || !lastInboundMessageBuffer().isEmpty() || - hasReadableOutboundBuffer(); - } - - /** - * Write data to the inbound of this {@link Channel}. - * - * @param data data that should be written - * @return bufferReadable returns {@code true} if the write operation did add something to the the inbound buffer - */ - public boolean writeInbound(O data) { - ensureOpen(); - writeInbound0(data); - pipeline().fireInboundBufferUpdated(); - runPendingTasks(); - checkException(); - return lastInboundByteBuffer().isReadable() || !lastInboundMessageBuffer().isEmpty(); - } - - /** - * Write data to the outbound of this {@link Channel}. - * - * @param data data that should be written - * @return bufferReadable returns {@code true} if the write operation did add something to the the outbound buffer - */ - public boolean writeOutbound(Object data) { - ensureOpen(); - ChannelFuture future = write(data); - assert future.isDone(); - if (future.cause() != null) { - recordException(future.cause()); + @Override + protected int doWrite(MessageList msgs, int index) throws Exception { + int size = msgs.size(); + for (int i = index; i < size; i ++) { + lastOutboundBuffer.add(msgs.get(i)); } - runPendingTasks(); - checkException(); - return hasReadableOutboundBuffer(); + return size - index; } - /** - * Returns {@code true} if the outbound buffer hold some data which can be read - */ - protected abstract boolean hasReadableOutboundBuffer(); - - /** - * Add the data to the inbound buffer. - */ - protected abstract void writeInbound0(O data); - private class DefaultUnsafe extends AbstractUnsafe { @Override - public void connect(SocketAddress remoteAddress, - SocketAddress localAddress, ChannelPromise promise) { + public void connect(SocketAddress remoteAddress, SocketAddress localAddress, ChannelPromise promise) { promise.setSuccess(); } } - private final class LastInboundMessageHandler extends ChannelStateHandlerAdapter - implements ChannelInboundMessageHandler { + private final class LastInboundHandler extends ChannelInboundHandlerAdapter { @Override - public MessageBuf newInboundBuffer(ChannelHandlerContext ctx) throws Exception { - return lastInboundMessageBuffer; + public void messageReceived(ChannelHandlerContext ctx, MessageList msgs) throws Exception { + int size = msgs.size(); + for (int i = 0; i < size; i ++) { + lastInboundBuffer.add(msgs.get(i)); + } } @Override - public void inboundBufferUpdated(ChannelHandlerContext ctx) throws Exception { - // Do nothing. - } - - @Override - public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) - throws Exception { + public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { recordException(cause); } } - - private final class LastInboundByteHandler extends ChannelStateHandlerAdapter - implements ChannelInboundByteHandler { - @Override - public ByteBuf newInboundBuffer(ChannelHandlerContext ctx) throws Exception { - return lastInboundByteBuffer; - } - - @Override - public void discardInboundReadBytes(ChannelHandlerContext ctx) throws Exception { - // nothing - } - - @Override - public void inboundBufferUpdated(ChannelHandlerContext ctx) throws Exception { - // No nothing - } - } } diff --git a/transport/src/main/java/io/netty/channel/embedded/EmbeddedMessageChannel.java b/transport/src/main/java/io/netty/channel/embedded/EmbeddedMessageChannel.java deleted file mode 100644 index ecb9b447c4..0000000000 --- a/transport/src/main/java/io/netty/channel/embedded/EmbeddedMessageChannel.java +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright 2012 The Netty Project - * - * The Netty Project licenses this file to you under the Apache License, - * version 2.0 (the "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. - */ -package io.netty.channel.embedded; - -import io.netty.buffer.BufType; -import io.netty.buffer.MessageBuf; -import io.netty.buffer.Unpooled; -import io.netty.channel.Channel; -import io.netty.channel.ChannelHandler; -import io.netty.channel.ChannelMetadata; -import io.netty.channel.ChannelPipeline; - -/** - * Embedded {@link Channel} which operates on messages which can be of any time. - */ -public class EmbeddedMessageChannel extends AbstractEmbeddedChannel { - - private static final ChannelMetadata METADATA = new ChannelMetadata(BufType.MESSAGE, false); - - /** - * Create a new instance with the given {@link ChannelHandler}s in the {@link ChannelPipeline} - */ - public EmbeddedMessageChannel(ChannelHandler... handlers) { - super(Unpooled.messageBuffer(), handlers); - } - - @Override - public ChannelMetadata metadata() { - return METADATA; - } - - @Override - public MessageBuf inboundBuffer() { - return pipeline().inboundMessageBuffer(); - } - - @Override - @SuppressWarnings("unchecked") - public MessageBuf lastOutboundBuffer() { - return (MessageBuf) lastOutboundBuffer; - } - - @Override - public Object readOutbound() { - return lastOutboundBuffer().poll(); - } - - @Override - protected void writeInbound0(Object data) { - inboundBuffer().add(data); - } - - @Override - protected boolean hasReadableOutboundBuffer() { - return !lastOutboundBuffer().isEmpty(); - } - - @Override - protected void doFlushMessageBuffer(MessageBuf buf) throws Exception { - buf.drainTo(lastOutboundBuffer()); - } -} diff --git a/transport/src/main/java/io/netty/channel/group/ChannelGroup.java b/transport/src/main/java/io/netty/channel/group/ChannelGroup.java index a8230de2aa..b034d94377 100644 --- a/transport/src/main/java/io/netty/channel/group/ChannelGroup.java +++ b/transport/src/main/java/io/netty/channel/group/ChannelGroup.java @@ -20,9 +20,9 @@ import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import io.netty.channel.Channel; import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.ChannelStateHandlerAdapter; +import io.netty.channel.ChannelInboundHandlerAdapter; import io.netty.channel.EventLoop; -import io.netty.channel.FileRegion; +import io.netty.channel.MessageList; import io.netty.channel.ServerChannel; import io.netty.util.CharsetUtil; @@ -78,7 +78,7 @@ import java.util.Set; * b.releaseExternalResources(); * } * - * public class MyHandler extends {@link ChannelStateHandlerAdapter} { + * public class MyHandler extends {@link ChannelInboundHandlerAdapter} { * {@code @Override} * public void channelActive({@link ChannelHandlerContext} ctx) { * // closed on shutdown. @@ -117,23 +117,17 @@ public interface ChannelGroup extends Set, Comparable { ChannelGroupFuture write(Object message); /** - * Writes the specified {@link FileRegion} to all {@link Channel}s in this - * group. Please note that this operation is asynchronous as - * {@link Channel#sendFile(FileRegion)} is. + * Writes the specified {@code messages} to all {@link Channel}s in this + * group. If the specified {@code messages} are an instance of + * {@link ByteBuf}, it is automatically + * {@linkplain ByteBuf#duplicate() duplicated} to avoid a race + * condition. Please note that this operation is asynchronous as + * {@link Channel#write(Object)} is. * * @return the {@link ChannelGroupFuture} instance that notifies when * the operation is done for all channels */ - ChannelGroupFuture sendFile(FileRegion region); - - /** - * Flush all {@link Channel} in this group. Please note that this operation - * is asynchronous as {@link Channel#flush()} is. - * - * @return the {@link ChannelGroupFuture} instance that notifies when - * the operation is done for all channels - */ - ChannelGroupFuture flush(); + ChannelGroupFuture write(MessageList messages); /** * Disconnects all {@link Channel}s in this group from their remote peers. diff --git a/transport/src/main/java/io/netty/channel/group/DefaultChannelGroup.java b/transport/src/main/java/io/netty/channel/group/DefaultChannelGroup.java index 930aa6894e..036ef3cf4c 100644 --- a/transport/src/main/java/io/netty/channel/group/DefaultChannelGroup.java +++ b/transport/src/main/java/io/netty/channel/group/DefaultChannelGroup.java @@ -15,11 +15,11 @@ */ package io.netty.channel.group; -import io.netty.buffer.BufUtil; +import io.netty.buffer.ByteBufUtil; import io.netty.channel.Channel; import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelFutureListener; -import io.netty.channel.FileRegion; +import io.netty.channel.MessageList; import io.netty.channel.ServerChannel; import io.netty.util.concurrent.EventExecutor; import io.netty.util.concurrent.ImmediateEventExecutor; @@ -233,37 +233,27 @@ public class DefaultChannelGroup extends AbstractSet implements Channel Map futures = new LinkedHashMap(size()); for (Channel c: nonServerChannels.values()) { - BufUtil.retain(message); + ByteBufUtil.retain(message); futures.put(c.id(), c.write(message)); } - BufUtil.release(message); + ByteBufUtil.release(message); return new DefaultChannelGroupFuture(this, futures, executor); } @Override - public ChannelGroupFuture sendFile(FileRegion region) { - if (region == null) { - throw new NullPointerException("region"); + public ChannelGroupFuture write(MessageList messages) { + if (messages == null) { + throw new NullPointerException("messages"); } Map futures = new LinkedHashMap(size()); for (Channel c: nonServerChannels.values()) { - BufUtil.retain(region); - futures.put(c.id(), c.sendFile(region)); - } - - BufUtil.release(region); - return new DefaultChannelGroupFuture(this, futures, executor); - } - - @Override - public ChannelGroupFuture flush() { - Map futures = new LinkedHashMap(size()); - for (Channel c: nonServerChannels.values()) { - futures.put(c.id(), c.flush()); + MessageList messagesCopy = messages.retainAll().copy(); + futures.put(c.id(), c.write(messagesCopy)); } + messages.releaseAllAndRecycle(); return new DefaultChannelGroupFuture(this, futures, executor); } diff --git a/transport/src/main/java/io/netty/channel/local/LocalChannel.java b/transport/src/main/java/io/netty/channel/local/LocalChannel.java index 9a7f0d03a2..116f6905c1 100755 --- a/transport/src/main/java/io/netty/channel/local/LocalChannel.java +++ b/transport/src/main/java/io/netty/channel/local/LocalChannel.java @@ -15,8 +15,6 @@ */ package io.netty.channel.local; -import io.netty.buffer.BufType; -import io.netty.buffer.MessageBuf; import io.netty.channel.AbstractChannel; import io.netty.channel.Channel; import io.netty.channel.ChannelConfig; @@ -26,6 +24,7 @@ import io.netty.channel.ChannelPipeline; import io.netty.channel.ChannelPromise; import io.netty.channel.DefaultChannelConfig; import io.netty.channel.EventLoop; +import io.netty.channel.MessageList; import io.netty.channel.SingleThreadEventLoop; import io.netty.util.concurrent.SingleThreadEventExecutor; @@ -34,14 +33,15 @@ import java.nio.channels.AlreadyConnectedException; import java.nio.channels.ClosedChannelException; import java.nio.channels.ConnectionPendingException; import java.nio.channels.NotYetConnectedException; -import java.util.Collections; +import java.util.ArrayDeque; +import java.util.Queue; /** * A {@link Channel} for the local transport. */ public class LocalChannel extends AbstractChannel { - private static final ChannelMetadata METADATA = new ChannelMetadata(BufType.MESSAGE, false); + private static final ChannelMetadata METADATA = new ChannelMetadata(false); private static final int MAX_READER_STACK_DEPTH = 8; private static final ThreadLocal READER_STACK_DEPTH = new ThreadLocal() { @@ -52,11 +52,18 @@ public class LocalChannel extends AbstractChannel { }; private final ChannelConfig config = new DefaultChannelConfig(this); + private final Queue> inboundBuffer = new ArrayDeque>(); private final Runnable readTask = new Runnable() { @Override public void run() { ChannelPipeline pipeline = pipeline(); - pipeline.fireInboundBufferUpdated(); + for (;;) { + MessageList m = inboundBuffer.poll(); + if (m == null) { + break; + } + pipeline.fireMessageReceived(m); + } pipeline.fireChannelReadSuspended(); } }; @@ -236,8 +243,8 @@ public class LocalChannel extends AbstractChannel { } ChannelPipeline pipeline = pipeline(); - MessageBuf buf = pipeline.inboundMessageBuffer(); - if (buf.isEmpty()) { + Queue> inboundBuffer = this.inboundBuffer; + if (inboundBuffer.isEmpty()) { readInProgress = true; return; } @@ -246,7 +253,13 @@ public class LocalChannel extends AbstractChannel { if (stackDepth < MAX_READER_STACK_DEPTH) { READER_STACK_DEPTH.set(stackDepth + 1); try { - pipeline.fireInboundBufferUpdated(); + for (;;) { + MessageList received = inboundBuffer.poll(); + if (received == null) { + break; + } + pipeline.fireMessageReceived(received); + } pipeline.fireChannelReadSuspended(); } finally { READER_STACK_DEPTH.set(stackDepth); @@ -257,7 +270,7 @@ public class LocalChannel extends AbstractChannel { } @Override - protected void doFlushMessageBuffer(MessageBuf buf) throws Exception { + protected int doWrite(MessageList msgs, int index) throws Exception { if (state < 2) { throw new NotYetConnectedException(); } @@ -268,28 +281,37 @@ public class LocalChannel extends AbstractChannel { final LocalChannel peer = this.peer; final ChannelPipeline peerPipeline = peer.pipeline(); final EventLoop peerLoop = peer.eventLoop(); + final int size = msgs.size(); + + // Use a copy because the original msgs will be recycled by AbstractChannel. + final MessageList msgsCopy = msgs.copy(); if (peerLoop == eventLoop()) { - buf.drainTo(peerPipeline.inboundMessageBuffer()); + peer.inboundBuffer.add(msgsCopy); finishPeerRead(peer, peerPipeline); } else { - final Object[] msgs = buf.toArray(); - buf.clear(); peerLoop.execute(new Runnable() { @Override public void run() { - MessageBuf buf = peerPipeline.inboundMessageBuffer(); - Collections.addAll(buf, msgs); + peer.inboundBuffer.add(msgsCopy); finishPeerRead(peer, peerPipeline); } }); } + + return size - index; } private static void finishPeerRead(LocalChannel peer, ChannelPipeline peerPipeline) { if (peer.readInProgress) { peer.readInProgress = false; - peerPipeline.fireInboundBufferUpdated(); + for (;;) { + MessageList received = peer.inboundBuffer.poll(); + if (received == null) { + break; + } + peerPipeline.fireMessageReceived(received); + } peerPipeline.fireChannelReadSuspended(); } } diff --git a/transport/src/main/java/io/netty/channel/local/LocalServerChannel.java b/transport/src/main/java/io/netty/channel/local/LocalServerChannel.java index 5366827ff0..7f0aabdac5 100755 --- a/transport/src/main/java/io/netty/channel/local/LocalServerChannel.java +++ b/transport/src/main/java/io/netty/channel/local/LocalServerChannel.java @@ -15,17 +15,19 @@ */ package io.netty.channel.local; -import io.netty.buffer.MessageBuf; import io.netty.channel.AbstractServerChannel; import io.netty.channel.ChannelConfig; import io.netty.channel.ChannelPipeline; import io.netty.channel.DefaultChannelConfig; import io.netty.channel.EventLoop; +import io.netty.channel.MessageList; import io.netty.channel.ServerChannel; import io.netty.channel.SingleThreadEventLoop; import io.netty.util.concurrent.SingleThreadEventExecutor; import java.net.SocketAddress; +import java.util.ArrayDeque; +import java.util.Queue; /** * A {@link ServerChannel} for the local transport which allows in VM communication. @@ -33,6 +35,7 @@ import java.net.SocketAddress; public class LocalServerChannel extends AbstractServerChannel { private final ChannelConfig config = new DefaultChannelConfig(this); + private final Queue inboundBuffer = new ArrayDeque(); private final Runnable shutdownHook = new Runnable() { @Override public void run() { @@ -138,13 +141,15 @@ public class LocalServerChannel extends AbstractServerChannel { } ChannelPipeline pipeline = pipeline(); - MessageBuf buf = pipeline.inboundMessageBuffer(); - if (buf.isEmpty()) { + Queue inboundBuffer = this.inboundBuffer; + if (inboundBuffer.isEmpty()) { acceptInProgress = true; return; } - pipeline.fireInboundBufferUpdated(); + Object[] messages = inboundBuffer.toArray(); + inboundBuffer.clear(); + pipeline.fireMessageReceived(messages); pipeline.fireChannelReadSuspended(); } @@ -157,10 +162,19 @@ public class LocalServerChannel extends AbstractServerChannel { private void serve0(final LocalChannel child) { if (eventLoop().inEventLoop()) { final ChannelPipeline pipeline = pipeline(); - pipeline.inboundMessageBuffer().add(child); + inboundBuffer.add(child); if (acceptInProgress) { acceptInProgress = false; - pipeline.fireInboundBufferUpdated(); + MessageList messages = MessageList.newInstance(); + for (;;) { + Object m = inboundBuffer.poll(); + if (m == null) { + break; + } + messages.add(m); + } + inboundBuffer.clear(); + pipeline.fireMessageReceived(messages); pipeline.fireChannelReadSuspended(); } } else { diff --git a/transport/src/main/java/io/netty/channel/nio/AbstractNioByteChannel.java b/transport/src/main/java/io/netty/channel/nio/AbstractNioByteChannel.java index a591073d26..93fea7f0b8 100755 --- a/transport/src/main/java/io/netty/channel/nio/AbstractNioByteChannel.java +++ b/transport/src/main/java/io/netty/channel/nio/AbstractNioByteChannel.java @@ -17,15 +17,17 @@ package io.netty.channel.nio; import io.netty.buffer.ByteBuf; import io.netty.channel.Channel; +import io.netty.channel.ChannelConfig; import io.netty.channel.ChannelOption; import io.netty.channel.ChannelPipeline; +import io.netty.channel.FileRegion; +import io.netty.channel.MessageList; +import io.netty.channel.RecvByteBufAllocator; import io.netty.channel.socket.ChannelInputShutdownEvent; import java.io.IOException; -import java.nio.channels.ClosedChannelException; import java.nio.channels.SelectableChannel; import java.nio.channels.SelectionKey; -import java.nio.channels.WritableByteChannel; /** * {@link AbstractNioChannel} base class for {@link Channel}s that operate on bytes. @@ -50,11 +52,14 @@ public abstract class AbstractNioByteChannel extends AbstractNioChannel { } private final class NioByteUnsafe extends AbstractNioUnsafe { + private RecvByteBufAllocator.Handle allocHandle; + @Override public void read() { assert eventLoop().inEventLoop(); final SelectionKey key = selectionKey(); - if (!config().isAutoRead()) { + final ChannelConfig config = config(); + if (!config.isAutoRead()) { int interestOps = key.interestOps(); if ((interestOps & readInterestOp) != 0) { // only remove readInterestOp if needed @@ -63,62 +68,37 @@ public abstract class AbstractNioByteChannel extends AbstractNioChannel { } final ChannelPipeline pipeline = pipeline(); - final ByteBuf byteBuf = pipeline.inboundByteBuffer(); - boolean closed = false; - boolean read = false; - boolean firedChannelReadSuspended = false; - try { - expandReadBuffer(byteBuf); - loop: for (;;) { - int localReadAmount = doReadBytes(byteBuf); - if (localReadAmount > 0) { - read = true; - } else if (localReadAmount < 0) { - closed = true; - break; - } - switch (expandReadBuffer(byteBuf)) { - case 0: - // Read all - stop reading. - break loop; - case 1: - // Keep reading until everything is read. - break; - case 2: - // Let the inbound handler drain the buffer and continue reading. - if (read) { - read = false; - pipeline.fireInboundBufferUpdated(); - if (!byteBuf.isWritable()) { - throw new IllegalStateException( - "an inbound handler whose buffer is full must consume at " + - "least one byte."); - } - } - if (!config().isAutoRead()) { - // stop reading until next Channel.read() call - // See https://github.com/netty/netty/issues/1363 - break loop; - } - } + RecvByteBufAllocator.Handle allocHandle = this.allocHandle; + if (allocHandle == null) { + this.allocHandle = allocHandle = config.getRecvByteBufAllocator().newHandle(); + } + + ByteBuf byteBuf = allocHandle.allocate(config.getAllocator()); + boolean closed = false; + Throwable exception = null; + try { + int localReadAmount = doReadBytes(byteBuf); + if (localReadAmount < 0) { + closed = true; } } catch (Throwable t) { - if (read) { - read = false; - pipeline.fireInboundBufferUpdated(); + exception = t; + } finally { + int readBytes = byteBuf.readableBytes(); + allocHandle.record(readBytes); + if (readBytes != 0) { + pipeline.fireMessageReceived(byteBuf); + } else { + byteBuf.release(); } - if (t instanceof IOException) { - closed = true; - } else if (!closed) { - firedChannelReadSuspended = true; - pipeline.fireChannelReadSuspended(); - } - pipeline().fireExceptionCaught(t); - } finally { - if (read) { - pipeline.fireInboundBufferUpdated(); + if (exception != null) { + if (exception instanceof IOException) { + closed = true; + } + + pipeline().fireExceptionCaught(exception); } if (closed) { @@ -131,7 +111,7 @@ public abstract class AbstractNioByteChannel extends AbstractNioChannel { close(voidPromise()); } } - } else if (!firedChannelReadSuspended) { + } else { pipeline.fireChannelReadSuspended(); } } @@ -139,86 +119,55 @@ public abstract class AbstractNioByteChannel extends AbstractNioChannel { } @Override - protected void doFlushByteBuffer(ByteBuf buf) throws Exception { - for (int i = config().getWriteSpinCount() - 1; i >= 0; i --) { - int localFlushedAmount = doWriteBytes(buf, i == 0); - if (localFlushedAmount > 0 || !buf.isReadable()) { - break; - } - } - } + protected int doWrite(MessageList msgs, int index) throws Exception { + Object msg = msgs.get(index); - @Override - protected void doFlushFileRegion(final FlushTask task) throws Exception { - if (javaChannel() instanceof WritableByteChannel) { - TransferTask transferTask = new TransferTask(task, (WritableByteChannel) javaChannel()); - transferTask.transfer(); + if (msg instanceof ByteBuf) { + ByteBuf buf = (ByteBuf) msg; + for (int i = config().getWriteSpinCount() - 1; i >= 0; i --) { + int localFlushedAmount = doWriteBytes(buf, i == 0); + if (localFlushedAmount > 0 || !buf.isReadable()) { + break; + } + } + // We may could optimize this to write multiple buffers at once (scattering) + if (!buf.isReadable()) { + buf.release(); + return 1; + } + } else if (msg instanceof FileRegion) { + FileRegion region = (FileRegion) msg; + + for (int i = config().getWriteSpinCount() - 1; i >= 0; i --) { + long localFlushedAmount = doWriteFileRegion(region, i == 0); + if (localFlushedAmount == -1) { + checkEOF(region); + return 1; + } + if (localFlushedAmount > 0) { + break; + } + } + if (region.transfered() >= region.count()) { + region.release(); + return 1; + } } else { - throw new UnsupportedOperationException("Underlying Channel is not of instance " - + WritableByteChannel.class); + throw new UnsupportedOperationException("Not support writing of message " + msg); } + + return 0; } - private final class TransferTask implements NioTask { - private long writtenBytes; - private final FlushTask task; - private final WritableByteChannel wch; - - TransferTask(FlushTask task, WritableByteChannel wch) { - this.task = task; - this.wch = wch; - } - - void transfer() { - try { - for (;;) { - long localWrittenBytes = task.region().transferTo(wch, writtenBytes); - if (localWrittenBytes == 0) { - // reschedule for write once the channel is writable again - eventLoop().executeWhenWritable( - AbstractNioByteChannel.this, this); - return; - } else if (localWrittenBytes == -1) { - checkEOF(task.region(), writtenBytes); - task.setSuccess(); - return; - } else { - writtenBytes += localWrittenBytes; - task.setProgress(writtenBytes); - - if (writtenBytes >= task.region().count()) { - task.setSuccess(); - return; - } - } - } - } catch (Throwable cause) { - task.setFailure(cause); - } - } - - @Override - public void channelReady(SelectableChannel ch, SelectionKey key) throws Exception { - transfer(); - } - - @Override - public void channelUnregistered(SelectableChannel ch, Throwable cause) throws Exception { - if (cause != null) { - task.setFailure(cause); - return; - } - - if (writtenBytes < task.region().count()) { - if (!isOpen()) { - task.setFailure(new ClosedChannelException()); - } else { - task.setFailure(new IllegalStateException( - "Channel was unregistered before the region could be fully written")); - } - } - } - } + /** + * Write a {@link FileRegion} + * + * @param region the {@link FileRegion} from which the bytes should be written + * @param lastSpin {@code true} if this is the last write try + * @return amount the amount of written bytes + * @throws Exception thrown if an error accour + */ + protected abstract long doWriteFileRegion(FileRegion region, boolean lastSpin) throws Exception; /** * Read bytes into the given {@link ByteBuf} and return the amount. diff --git a/transport/src/main/java/io/netty/channel/nio/AbstractNioMessageChannel.java b/transport/src/main/java/io/netty/channel/nio/AbstractNioMessageChannel.java index c5cce02bfb..180cf07024 100755 --- a/transport/src/main/java/io/netty/channel/nio/AbstractNioMessageChannel.java +++ b/transport/src/main/java/io/netty/channel/nio/AbstractNioMessageChannel.java @@ -15,9 +15,9 @@ */ package io.netty.channel.nio; -import io.netty.buffer.MessageBuf; import io.netty.channel.Channel; import io.netty.channel.ChannelPipeline; +import io.netty.channel.MessageList; import java.io.IOException; import java.nio.channels.SelectableChannel; @@ -28,9 +28,6 @@ import java.nio.channels.SelectionKey; */ public abstract class AbstractNioMessageChannel extends AbstractNioChannel { - // Hard coded for now. - private static final int READ_BATCH_SIZE = 16; - /** * @see {@link AbstractNioChannel#AbstractNioChannel(Channel, Integer, SelectableChannel, int)} */ @@ -58,93 +55,73 @@ public abstract class AbstractNioMessageChannel extends AbstractNioChannel { } final ChannelPipeline pipeline = pipeline(); - final MessageBuf msgBuf = pipeline.inboundMessageBuffer(); boolean closed = false; - boolean read = false; - boolean firedChannelReadSuspended = false; + MessageList msgBuf = MessageList.newInstance(); + Throwable exception = null; loop: for (;;) { - int reads = 0; - try { for (;;) { - int localReadAmount = doReadMessages(msgBuf); - if (localReadAmount > 0) { - read = true; - } else if (localReadAmount == 0) { - break loop; - } else if (localReadAmount < 0) { - closed = true; + int localRead = doReadMessages(msgBuf); + if (localRead == 0) { break loop; } - - if (reads++ > READ_BATCH_SIZE) { - break; + if (localRead < 0) { + closed = true; + break loop; } if (!config().isAutoRead()) { break loop; } } } catch (Throwable t) { - if (read) { - read = false; - pipeline.fireInboundBufferUpdated(); - } - - if (t instanceof IOException) { - closed = true; - } else if (!closed) { - firedChannelReadSuspended = true; - pipeline.fireChannelReadSuspended(); - } - - pipeline().fireExceptionCaught(t); - - // break the loop now + exception = t; break; - } finally { - if (read) { - pipeline.fireInboundBufferUpdated(); - } - if (closed && isOpen()) { - close(voidPromise()); - } else if (!firedChannelReadSuspended) { - pipeline.fireChannelReadSuspended(); - } } } + + pipeline.fireMessageReceived(msgBuf); + + if (exception != null) { + if (exception instanceof IOException) { + closed = true; + } + + pipeline().fireExceptionCaught(exception); + } + + if (closed) { + if (isOpen()) { + close(voidPromise()); + } + } else { + pipeline.fireChannelReadSuspended(); + } } } @Override - protected void doFlushMessageBuffer(MessageBuf buf) throws Exception { + protected int doWrite(MessageList msgs, int index) throws Exception { final int writeSpinCount = config().getWriteSpinCount() - 1; - while (!buf.isEmpty()) { - boolean wrote = false; - for (int i = writeSpinCount; i >= 0; i --) { - int localFlushedAmount = doWriteMessages(buf, i == 0); - if (localFlushedAmount > 0) { - wrote = true; - break; - } - } - - if (!wrote) { - break; + for (int i = writeSpinCount; i >= 0; i --) { + int written = doWriteMessages(msgs, index, i == 0); + if (written > 0) { + return written; } } + return 0; } /** - * Read messages into the given {@link MessageBuf} and return the amount. + * Read messages into the given array and return the amount which was read. */ - protected abstract int doReadMessages(MessageBuf buf) throws Exception; + protected abstract int doReadMessages(MessageList buf) throws Exception; /** - * Write messages form the given {@link MessageBuf} to the underlying {@link java.nio.channels.Channel}. - * @param buf the {@link MessageBuf} from which the bytes should be written + * Write messages to the underlying {@link java.nio.channels.Channel}. + * @param msg Object to write * @param lastSpin {@code true} if this is the last write try - * @return amount the amount of written bytes + * @return written the amount of written messages * @throws Exception thrown if an error accour */ - protected abstract int doWriteMessages(MessageBuf buf, boolean lastSpin) throws Exception; + protected abstract int doWriteMessages(MessageList msg, int index, boolean lastSpin) throws Exception; } diff --git a/transport/src/main/java/io/netty/channel/oio/AbstractOioByteChannel.java b/transport/src/main/java/io/netty/channel/oio/AbstractOioByteChannel.java index 37857503aa..ef8bcb9534 100755 --- a/transport/src/main/java/io/netty/channel/oio/AbstractOioByteChannel.java +++ b/transport/src/main/java/io/netty/channel/oio/AbstractOioByteChannel.java @@ -15,12 +15,13 @@ */ package io.netty.channel.oio; -import io.netty.buffer.BufType; import io.netty.buffer.ByteBuf; import io.netty.channel.Channel; import io.netty.channel.ChannelMetadata; import io.netty.channel.ChannelOption; import io.netty.channel.ChannelPipeline; +import io.netty.channel.FileRegion; +import io.netty.channel.MessageList; import io.netty.channel.socket.ChannelInputShutdownEvent; import java.io.IOException; @@ -31,7 +32,7 @@ import java.io.IOException; public abstract class AbstractOioByteChannel extends AbstractOioChannel { private volatile boolean inputShutdown; - private static final ChannelMetadata METADATA = new ChannelMetadata(BufType.BYTE, false); + private static final ChannelMetadata METADATA = new ChannelMetadata(false); /** * @see AbstractOioByteChannel#AbstractOioByteChannel(Channel, Integer) @@ -72,7 +73,9 @@ public abstract class AbstractOioByteChannel extends AbstractOioChannel { } final ChannelPipeline pipeline = pipeline(); - final ByteBuf byteBuf = pipeline.inboundByteBuffer(); + + // TODO: calculate size as in 3.x + ByteBuf byteBuf = alloc().buffer(); boolean closed = false; boolean read = false; boolean firedInboundBufferSuspeneded = false; @@ -96,12 +99,8 @@ public abstract class AbstractOioByteChannel extends AbstractOioChannel { if (capacity == maxCapacity) { if (read) { read = false; - pipeline.fireInboundBufferUpdated(); - if (!byteBuf.isWritable()) { - throw new IllegalStateException( - "an inbound handler whose buffer is full must consume at " + - "least one byte."); - } + pipeline.fireMessageReceived(byteBuf); + byteBuf = alloc().buffer(); } } else { final int writerIndex = byteBuf.writerIndex(); @@ -121,7 +120,7 @@ public abstract class AbstractOioByteChannel extends AbstractOioChannel { } catch (Throwable t) { if (read) { read = false; - pipeline.fireInboundBufferUpdated(); + pipeline.fireMessageReceived(byteBuf); } if (t instanceof IOException) { @@ -135,7 +134,10 @@ public abstract class AbstractOioByteChannel extends AbstractOioChannel { } } finally { if (read) { - pipeline.fireInboundBufferUpdated(); + pipeline.fireMessageReceived(byteBuf); + } else { + // nothing read into the buffer so release it + byteBuf.release(); } if (closed) { inputShutdown = true; @@ -153,11 +155,23 @@ public abstract class AbstractOioByteChannel extends AbstractOioChannel { } @Override - protected void doFlushByteBuffer(ByteBuf buf) throws Exception { - while (buf.isReadable()) { - doWriteBytes(buf); + protected int doWrite(MessageList msgs, int index) throws Exception { + Object msg = msgs.get(index); + if (msg instanceof ByteBuf) { + ByteBuf buf = (ByteBuf) msg; + while (buf.isReadable()) { + doWriteBytes(buf); + } + buf.release(); + return 1; + } else if (msg instanceof FileRegion) { + FileRegion region = (FileRegion) msg; + doWriteFileRegion(region); + region.release(); + return 1; + } else { + throw new UnsupportedOperationException(); } - buf.clear(); } /** @@ -182,4 +196,12 @@ public abstract class AbstractOioByteChannel extends AbstractOioChannel { * @throws Exception is thrown if an error accoured */ protected abstract void doWriteBytes(ByteBuf buf) throws Exception; + + /** + * Write the data which is hold by the {@link FileRegion} to the underlying Socket. + * + * @param region the {@link FileRegion} which holds the data to transfer + * @throws Exception is thrown if an error accoured + */ + protected abstract void doWriteFileRegion(FileRegion region) throws Exception; } diff --git a/transport/src/main/java/io/netty/channel/oio/AbstractOioMessageChannel.java b/transport/src/main/java/io/netty/channel/oio/AbstractOioMessageChannel.java index 22c7a4a2c6..36ae20987b 100755 --- a/transport/src/main/java/io/netty/channel/oio/AbstractOioMessageChannel.java +++ b/transport/src/main/java/io/netty/channel/oio/AbstractOioMessageChannel.java @@ -15,9 +15,9 @@ */ package io.netty.channel.oio; -import io.netty.buffer.MessageBuf; import io.netty.channel.Channel; import io.netty.channel.ChannelPipeline; +import io.netty.channel.MessageList; import java.io.IOException; @@ -26,9 +26,6 @@ import java.io.IOException; */ public abstract class AbstractOioMessageChannel extends AbstractOioChannel { - /** - * @see AbstractOioChannel#AbstractOioChannel(Channel, Integer) - */ protected AbstractOioMessageChannel(Channel parent, Integer id) { super(parent, id); } @@ -36,63 +33,39 @@ public abstract class AbstractOioMessageChannel extends AbstractOioChannel { @Override protected void doRead() { final ChannelPipeline pipeline = pipeline(); - final MessageBuf msgBuf = pipeline.inboundMessageBuffer(); boolean closed = false; - boolean read = false; - boolean firedChannelReadSuspended = false; + MessageList msgs = MessageList.newInstance(); + Throwable exception = null; try { - int localReadAmount = doReadMessages(msgBuf); - if (localReadAmount > 0) { - read = true; - } else if (localReadAmount < 0) { + int localReadAmount = doReadMessages(msgs); + if (localReadAmount < 0) { closed = true; } } catch (Throwable t) { - if (read) { - read = false; - pipeline.fireInboundBufferUpdated(); + exception = t; + } + + pipeline.fireMessageReceived(msgs); + + if (exception != null) { + if (exception instanceof IOException) { + closed = true; } - firedChannelReadSuspended = true; + + pipeline().fireExceptionCaught(exception); + } + + if (closed) { + if (isOpen()) { + unsafe().close(unsafe().voidPromise()); + } + } else { pipeline.fireChannelReadSuspended(); - pipeline.fireExceptionCaught(t); - if (t instanceof IOException) { - unsafe().close(unsafe().voidPromise()); - } - } finally { - if (read) { - pipeline.fireInboundBufferUpdated(); - } - if (!firedChannelReadSuspended) { - pipeline.fireChannelReadSuspended(); - } - if (closed && isOpen()) { - unsafe().close(unsafe().voidPromise()); - } - } - } - - @Override - protected void doFlushMessageBuffer(MessageBuf buf) throws Exception { - while (!buf.isEmpty()) { - doWriteMessages(buf); } } /** - * Read Objects from the underlying Socket. - * - * @param buf the {@link MessageBuf} into which the read objects will be written - * @return amount the number of objects read. This may return a negative amount if the underlying - * Socket was closed - * @throws Exception is thrown if an error accoured + * Read messages into the given array and return the amount which was read. */ - protected abstract int doReadMessages(MessageBuf buf) throws Exception; - - /** - * Write the Objects which is hold by the {@link MessageBuf} to the underlying Socket. - * - * @param buf the {@link MessageBuf} which holds the data to transfer - * @throws Exception is thrown if an error accoured - */ - protected abstract void doWriteMessages(MessageBuf buf) throws Exception; + protected abstract int doReadMessages(MessageList msgs) throws Exception; } diff --git a/transport/src/main/java/io/netty/channel/oio/OioByteStreamChannel.java b/transport/src/main/java/io/netty/channel/oio/OioByteStreamChannel.java index b71f900348..dd0d3ab294 100644 --- a/transport/src/main/java/io/netty/channel/oio/OioByteStreamChannel.java +++ b/transport/src/main/java/io/netty/channel/oio/OioByteStreamChannel.java @@ -17,6 +17,7 @@ package io.netty.channel.oio; import io.netty.buffer.ByteBuf; import io.netty.channel.Channel; +import io.netty.channel.FileRegion; import java.io.IOException; import java.io.InputStream; @@ -95,7 +96,7 @@ public abstract class OioByteStreamChannel extends AbstractOioByteChannel { } @Override - protected void doFlushFileRegion(FlushTask task) throws Exception { + protected void doWriteFileRegion(FileRegion region) throws Exception { OutputStream os = this.os; if (os == null) { throw new NotYetConnectedException(); @@ -106,17 +107,14 @@ public abstract class OioByteStreamChannel extends AbstractOioByteChannel { long written = 0; for (;;) { - long localWritten = task.region().transferTo(outChannel, written); + long localWritten = region.transferTo(outChannel, written); if (localWritten == -1) { - checkEOF(task.region(), written); - task.setSuccess(); + checkEOF(region); return; } written += localWritten; - task.setProgress(written); - if (written >= task.region().count()) { - task.setSuccess(); + if (written >= region.count()) { return; } } diff --git a/transport/src/main/java/io/netty/channel/socket/ChannelInputShutdownEvent.java b/transport/src/main/java/io/netty/channel/socket/ChannelInputShutdownEvent.java index 9d98ab16e1..40ed4140b5 100644 --- a/transport/src/main/java/io/netty/channel/socket/ChannelInputShutdownEvent.java +++ b/transport/src/main/java/io/netty/channel/socket/ChannelInputShutdownEvent.java @@ -16,11 +16,11 @@ package io.netty.channel.socket; import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.ChannelStateHandler; +import io.netty.channel.ChannelInboundHandler; /** * Special event which will be fired and passed to the - * {@link ChannelStateHandler#userEventTriggered(ChannelHandlerContext, Object)} methods once the input of + * {@link ChannelInboundHandler#userEventTriggered(ChannelHandlerContext, Object)} methods once the input of * a {@link SocketChannel} was shutdown and the {@link SocketChannelConfig#isAllowHalfClosure()} method returns * {@code true}. */ diff --git a/transport/src/main/java/io/netty/channel/socket/DatagramChannelConfig.java b/transport/src/main/java/io/netty/channel/socket/DatagramChannelConfig.java index 3ab48b8aeb..a626712376 100644 --- a/transport/src/main/java/io/netty/channel/socket/DatagramChannelConfig.java +++ b/transport/src/main/java/io/netty/channel/socket/DatagramChannelConfig.java @@ -18,6 +18,7 @@ package io.netty.channel.socket; import io.netty.buffer.ByteBufAllocator; import io.netty.channel.ChannelConfig; import io.netty.channel.ChannelOption; +import io.netty.channel.RecvByteBufAllocator; import java.net.InetAddress; import java.net.NetworkInterface; @@ -54,8 +55,6 @@ import java.net.StandardSocketOptions; * {@link ChannelOption#IP_MULTICAST_TTL}{@link #setTimeToLive(int)} * * {@link ChannelOption#IP_TOS}{@link #setTrafficClass(int)} - * - * {@link ChannelOption#UDP_RECEIVE_PACKET_SIZE}{@link #setReceivePacketSize(int)} * * */ @@ -81,18 +80,6 @@ public interface DatagramChannelConfig extends ChannelConfig { */ DatagramChannelConfig setReceiveBufferSize(int receiveBufferSize); - /** - * Gets the size of the {@link DatagramPacket#data()} which will be used to store the received data. - * This should match the maximal packet size that you expect to receive. - */ - int getReceivePacketSize(); - - /** - * Sets the size of the {@link DatagramPacket#data()} which will be used to store the received data. - * This should match the maximal packet size that you expect to receive. - */ - DatagramChannelConfig setReceivePacketSize(int receivePacketSize); - /** * Gets the {@link StandardSocketOptions#IP_TOS} option. */ @@ -178,8 +165,8 @@ public interface DatagramChannelConfig extends ChannelConfig { DatagramChannelConfig setAllocator(ByteBufAllocator allocator); @Override - DatagramChannelConfig setAutoRead(boolean autoRead); + DatagramChannelConfig setRecvByteBufAllocator(RecvByteBufAllocator allocator); @Override - DatagramChannelConfig setDefaultHandlerByteBufType(ChannelHandlerByteBufType type); + DatagramChannelConfig setAutoRead(boolean autoRead); } diff --git a/transport/src/main/java/io/netty/channel/socket/DefaultDatagramChannelConfig.java b/transport/src/main/java/io/netty/channel/socket/DefaultDatagramChannelConfig.java index 559a70c74c..a542754a0e 100644 --- a/transport/src/main/java/io/netty/channel/socket/DefaultDatagramChannelConfig.java +++ b/transport/src/main/java/io/netty/channel/socket/DefaultDatagramChannelConfig.java @@ -16,10 +16,11 @@ package io.netty.channel.socket; import io.netty.buffer.ByteBufAllocator; -import io.netty.channel.ChannelConfig; import io.netty.channel.ChannelException; import io.netty.channel.ChannelOption; import io.netty.channel.DefaultChannelConfig; +import io.netty.channel.FixedRecvByteBufAllocator; +import io.netty.channel.RecvByteBufAllocator; import io.netty.util.internal.PlatformDependent; import io.netty.util.internal.logging.InternalLogger; import io.netty.util.internal.logging.InternalLoggerFactory; @@ -41,10 +42,9 @@ public class DefaultDatagramChannelConfig extends DefaultChannelConfig implement private static final InternalLogger logger = InternalLoggerFactory.getInstance(DefaultDatagramChannelConfig.class); - private static final int DEFAULT_RECEIVE_PACKET_SIZE = 2048; + private static final RecvByteBufAllocator DEFAULT_RCVBUF_ALLOCATOR = new FixedRecvByteBufAllocator(2048); private final DatagramSocket javaSocket; - private volatile int receivePacketSize = DEFAULT_RECEIVE_PACKET_SIZE; /** * Creates a new instance. @@ -55,6 +55,7 @@ public class DefaultDatagramChannelConfig extends DefaultChannelConfig implement throw new NullPointerException("javaSocket"); } this.javaSocket = javaSocket; + setRecvByteBufAllocator(DEFAULT_RCVBUF_ALLOCATOR); } @Override @@ -62,7 +63,7 @@ public class DefaultDatagramChannelConfig extends DefaultChannelConfig implement return getOptions( super.getOptions(), SO_BROADCAST, SO_RCVBUF, SO_SNDBUF, SO_REUSEADDR, IP_MULTICAST_LOOP_DISABLED, - IP_MULTICAST_ADDR, IP_MULTICAST_IF, IP_MULTICAST_TTL, IP_TOS, UDP_RECEIVE_PACKET_SIZE); + IP_MULTICAST_ADDR, IP_MULTICAST_IF, IP_MULTICAST_TTL, IP_TOS); } @SuppressWarnings("unchecked") @@ -77,9 +78,6 @@ public class DefaultDatagramChannelConfig extends DefaultChannelConfig implement if (option == SO_SNDBUF) { return (T) Integer.valueOf(getSendBufferSize()); } - if (option == UDP_RECEIVE_PACKET_SIZE) { - return (T) Integer.valueOf(getReceivePacketSize()); - } if (option == SO_REUSEADDR) { return (T) Boolean.valueOf(isReuseAddress()); } @@ -126,8 +124,6 @@ public class DefaultDatagramChannelConfig extends DefaultChannelConfig implement setTimeToLive((Integer) value); } else if (option == IP_TOS) { setTrafficClass((Integer) value); - } else if (option == UDP_RECEIVE_PACKET_SIZE) { - setReceivePacketSize((Integer) value); } else { return super.setOption(option, value); } @@ -305,21 +301,6 @@ public class DefaultDatagramChannelConfig extends DefaultChannelConfig implement return this; } - @Override - public int getReceivePacketSize() { - return receivePacketSize; - } - - @Override - public DatagramChannelConfig setReceivePacketSize(int receivePacketSize) { - if (receivePacketSize <= 0) { - throw new IllegalArgumentException( - String.format("receivePacketSize: %d (expected: > 0)", receivePacketSize)); - } - this.receivePacketSize = receivePacketSize; - return this; - } - @Override public int getTimeToLive() { if (javaSocket instanceof MulticastSocket) { @@ -381,13 +362,24 @@ public class DefaultDatagramChannelConfig extends DefaultChannelConfig implement return (DatagramChannelConfig) super.setAllocator(allocator); } + @Override + public DatagramChannelConfig setRecvByteBufAllocator(RecvByteBufAllocator allocator) { + super.setRecvByteBufAllocator(allocator); + return this; + } + @Override public DatagramChannelConfig setAutoRead(boolean autoRead) { return (DatagramChannelConfig) super.setAutoRead(autoRead); } @Override - public DatagramChannelConfig setDefaultHandlerByteBufType(ChannelHandlerByteBufType type) { - return (DatagramChannelConfig) super.setDefaultHandlerByteBufType(type); + public DatagramChannelConfig setWriteBufferHighWaterMark(int writeBufferHighWaterMark) { + return (DatagramChannelConfig) super.setWriteBufferHighWaterMark(writeBufferHighWaterMark); + } + + @Override + public DatagramChannelConfig setWriteBufferLowWaterMark(int writeBufferLowWaterMark) { + return (DatagramChannelConfig) super.setWriteBufferLowWaterMark(writeBufferLowWaterMark); } } diff --git a/transport/src/main/java/io/netty/channel/socket/DefaultServerSocketChannelConfig.java b/transport/src/main/java/io/netty/channel/socket/DefaultServerSocketChannelConfig.java index e97752bf0d..02a92e89bf 100644 --- a/transport/src/main/java/io/netty/channel/socket/DefaultServerSocketChannelConfig.java +++ b/transport/src/main/java/io/netty/channel/socket/DefaultServerSocketChannelConfig.java @@ -19,6 +19,7 @@ import io.netty.buffer.ByteBufAllocator; import io.netty.channel.ChannelException; import io.netty.channel.ChannelOption; import io.netty.channel.DefaultChannelConfig; +import io.netty.channel.RecvByteBufAllocator; import io.netty.util.NetUtil; import java.net.ServerSocket; @@ -158,13 +159,24 @@ public class DefaultServerSocketChannelConfig extends DefaultChannelConfig return (ServerSocketChannelConfig) super.setAllocator(allocator); } + @Override + public ServerSocketChannelConfig setRecvByteBufAllocator(RecvByteBufAllocator allocator) { + super.setRecvByteBufAllocator(allocator); + return this; + } + @Override public ServerSocketChannelConfig setAutoRead(boolean autoRead) { return (ServerSocketChannelConfig) super.setAutoRead(autoRead); } @Override - public ServerSocketChannelConfig setDefaultHandlerByteBufType(ChannelHandlerByteBufType type) { - return (ServerSocketChannelConfig) super.setDefaultHandlerByteBufType(type); + public ServerSocketChannelConfig setWriteBufferHighWaterMark(int writeBufferHighWaterMark) { + return (ServerSocketChannelConfig) super.setWriteBufferHighWaterMark(writeBufferHighWaterMark); + } + + @Override + public ServerSocketChannelConfig setWriteBufferLowWaterMark(int writeBufferLowWaterMark) { + return (ServerSocketChannelConfig) super.setWriteBufferLowWaterMark(writeBufferLowWaterMark); } } diff --git a/transport/src/main/java/io/netty/channel/socket/DefaultSocketChannelConfig.java b/transport/src/main/java/io/netty/channel/socket/DefaultSocketChannelConfig.java index bbe14c825b..62cefb8899 100644 --- a/transport/src/main/java/io/netty/channel/socket/DefaultSocketChannelConfig.java +++ b/transport/src/main/java/io/netty/channel/socket/DefaultSocketChannelConfig.java @@ -20,6 +20,7 @@ import io.netty.channel.ChannelConfig; import io.netty.channel.ChannelException; import io.netty.channel.ChannelOption; import io.netty.channel.DefaultChannelConfig; +import io.netty.channel.RecvByteBufAllocator; import io.netty.util.internal.PlatformDependent; import java.net.Socket; @@ -293,13 +294,24 @@ public class DefaultSocketChannelConfig extends DefaultChannelConfig return (SocketChannelConfig) super.setAllocator(allocator); } + @Override + public SocketChannelConfig setRecvByteBufAllocator(RecvByteBufAllocator allocator) { + super.setRecvByteBufAllocator(allocator); + return this; + } + @Override public SocketChannelConfig setAutoRead(boolean autoRead) { return (SocketChannelConfig) super.setAutoRead(autoRead); } @Override - public SocketChannelConfig setDefaultHandlerByteBufType(ChannelHandlerByteBufType type) { - return (SocketChannelConfig) super.setDefaultHandlerByteBufType(type); + public SocketChannelConfig setWriteBufferHighWaterMark(int writeBufferHighWaterMark) { + return (SocketChannelConfig) super.setWriteBufferHighWaterMark(writeBufferHighWaterMark); + } + + @Override + public SocketChannelConfig setWriteBufferLowWaterMark(int writeBufferLowWaterMark) { + return (SocketChannelConfig) super.setWriteBufferLowWaterMark(writeBufferLowWaterMark); } } diff --git a/transport/src/main/java/io/netty/channel/socket/ServerSocketChannelConfig.java b/transport/src/main/java/io/netty/channel/socket/ServerSocketChannelConfig.java index 95c5ecc378..d9cf203ad1 100644 --- a/transport/src/main/java/io/netty/channel/socket/ServerSocketChannelConfig.java +++ b/transport/src/main/java/io/netty/channel/socket/ServerSocketChannelConfig.java @@ -17,6 +17,7 @@ package io.netty.channel.socket; import io.netty.buffer.ByteBufAllocator; import io.netty.channel.ChannelConfig; +import io.netty.channel.RecvByteBufAllocator; import java.net.ServerSocket; import java.net.StandardSocketOptions; @@ -92,8 +93,8 @@ public interface ServerSocketChannelConfig extends ChannelConfig { ServerSocketChannelConfig setAllocator(ByteBufAllocator allocator); @Override - ServerSocketChannelConfig setAutoRead(boolean autoRead); + ServerSocketChannelConfig setRecvByteBufAllocator(RecvByteBufAllocator allocator); @Override - ServerSocketChannelConfig setDefaultHandlerByteBufType(ChannelHandlerByteBufType type); + ServerSocketChannelConfig setAutoRead(boolean autoRead); } diff --git a/transport/src/main/java/io/netty/channel/socket/SocketChannelConfig.java b/transport/src/main/java/io/netty/channel/socket/SocketChannelConfig.java index 8dc827324a..1a0aa2a8d0 100644 --- a/transport/src/main/java/io/netty/channel/socket/SocketChannelConfig.java +++ b/transport/src/main/java/io/netty/channel/socket/SocketChannelConfig.java @@ -18,8 +18,9 @@ package io.netty.channel.socket; import io.netty.buffer.ByteBufAllocator; import io.netty.channel.ChannelConfig; import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.ChannelInboundHandler; import io.netty.channel.ChannelOption; -import io.netty.channel.ChannelStateHandler; +import io.netty.channel.RecvByteBufAllocator; import java.net.Socket; import java.net.StandardSocketOptions; @@ -149,7 +150,7 @@ public interface SocketChannelConfig extends ChannelConfig { * Sets whether the channel should not close itself when its remote peer shuts down output to * make the connection half-closed. If {@code true} the connection is not closed when the * remote peer shuts down output. Instead, - * {@link ChannelStateHandler#userEventTriggered(ChannelHandlerContext, Object)} + * {@link ChannelInboundHandler#userEventTriggered(ChannelHandlerContext, Object)} * is invoked with a {@link ChannelInputShutdownEvent} object. If {@code false}, the connection * is closed automatically. */ @@ -165,8 +166,8 @@ public interface SocketChannelConfig extends ChannelConfig { SocketChannelConfig setAllocator(ByteBufAllocator allocator); @Override - SocketChannelConfig setAutoRead(boolean autoRead); + SocketChannelConfig setRecvByteBufAllocator(RecvByteBufAllocator allocator); @Override - SocketChannelConfig setDefaultHandlerByteBufType(ChannelHandlerByteBufType type); + SocketChannelConfig setAutoRead(boolean autoRead); } diff --git a/transport/src/main/java/io/netty/channel/socket/aio/AioServerSocketChannel.java b/transport/src/main/java/io/netty/channel/socket/aio/AioServerSocketChannel.java index 89a6e99365..8e78141d86 100755 --- a/transport/src/main/java/io/netty/channel/socket/aio/AioServerSocketChannel.java +++ b/transport/src/main/java/io/netty/channel/socket/aio/AioServerSocketChannel.java @@ -15,13 +15,12 @@ */ package io.netty.channel.socket.aio; -import io.netty.buffer.BufType; -import io.netty.buffer.MessageBuf; import io.netty.channel.ChannelException; import io.netty.channel.ChannelMetadata; import io.netty.channel.ChannelPipeline; import io.netty.channel.ChannelPromise; import io.netty.channel.EventLoop; +import io.netty.channel.MessageList; import io.netty.channel.aio.AbstractAioChannel; import io.netty.channel.aio.AioCompletionHandler; import io.netty.channel.aio.AioEventLoopGroup; @@ -37,6 +36,7 @@ import java.nio.channels.AsynchronousChannelGroup; import java.nio.channels.AsynchronousCloseException; import java.nio.channels.AsynchronousServerSocketChannel; import java.nio.channels.AsynchronousSocketChannel; +import java.nio.channels.CompletionHandler; /** * {@link ServerSocketChannel} implementation which uses NIO2. @@ -45,9 +45,9 @@ import java.nio.channels.AsynchronousSocketChannel; */ public class AioServerSocketChannel extends AbstractAioChannel implements ServerSocketChannel { - private static final ChannelMetadata METADATA = new ChannelMetadata(BufType.MESSAGE, false); + private static final ChannelMetadata METADATA = new ChannelMetadata(false); - private static final AcceptHandler ACCEPT_HANDLER = new AcceptHandler(); + private final CompletionHandler acceptHandler = new AcceptHandler(this); private static final InternalLogger logger = InternalLoggerFactory.getInstance(AioServerSocketChannel.class); @@ -138,7 +138,7 @@ public class AioServerSocketChannel extends AbstractAioChannel implements Server } acceptInProgress = true; - javaChannel().accept(this, ACCEPT_HANDLER); + javaChannel().accept(null, acceptHandler); } @Override @@ -165,6 +165,11 @@ public class AioServerSocketChannel extends AbstractAioChannel implements Server throw new UnsupportedOperationException(); } + @Override + protected int doWrite(MessageList msgs, int index) throws Exception { + throw new UnsupportedOperationException(); + } + @Override protected Runnable doRegister() throws Exception { Runnable task = super.doRegister(); @@ -178,34 +183,25 @@ public class AioServerSocketChannel extends AbstractAioChannel implements Server } private static final class AcceptHandler - extends AioCompletionHandler { + extends AioCompletionHandler { + + AcceptHandler(AioServerSocketChannel channel) { + super(channel); + } @Override - protected void completed0(AsynchronousSocketChannel ch, AioServerSocketChannel channel) { + protected void completed0(AioServerSocketChannel channel, AsynchronousSocketChannel ch, Void attachment) { channel.acceptInProgress = false; ChannelPipeline pipeline = channel.pipeline(); - MessageBuf buffer = pipeline.inboundMessageBuffer(); - if (buffer.refCnt() == 0) { - try { - ch.close(); - } catch (IOException e) { - logger.warn( - "Failed to close a socket which was accepted while its server socket is being closed", - e); - } - return; - } - - // create the socket add it to the buffer and fire the event - buffer.add(new AioSocketChannel(channel, null, ch)); - pipeline.fireInboundBufferUpdated(); + // Create a new Netty channel from a JDK channel and trigger events. + pipeline.fireMessageReceived(new AioSocketChannel(channel, null, ch)); pipeline.fireChannelReadSuspended(); } @Override - protected void failed0(Throwable t, AioServerSocketChannel channel) { + protected void failed0(AioServerSocketChannel channel, Throwable t, Void attachment) { channel.acceptInProgress = false; boolean asyncClosed = false; if (t instanceof AsynchronousCloseException) { diff --git a/transport/src/main/java/io/netty/channel/socket/aio/AioServerSocketChannelConfig.java b/transport/src/main/java/io/netty/channel/socket/aio/AioServerSocketChannelConfig.java index be909e8aff..84b87d0f73 100644 --- a/transport/src/main/java/io/netty/channel/socket/aio/AioServerSocketChannelConfig.java +++ b/transport/src/main/java/io/netty/channel/socket/aio/AioServerSocketChannelConfig.java @@ -19,6 +19,7 @@ import io.netty.buffer.ByteBufAllocator; import io.netty.channel.ChannelException; import io.netty.channel.ChannelOption; import io.netty.channel.DefaultChannelConfig; +import io.netty.channel.RecvByteBufAllocator; import io.netty.channel.socket.ServerSocketChannelConfig; import io.netty.util.NetUtil; import io.netty.util.internal.PlatformDependent; @@ -218,6 +219,12 @@ final class AioServerSocketChannelConfig extends DefaultChannelConfig implements return this; } + @Override + public AioServerSocketChannelConfig setRecvByteBufAllocator(RecvByteBufAllocator allocator) { + super.setRecvByteBufAllocator(allocator); + return this; + } + @Override public AioServerSocketChannelConfig setAutoRead(boolean autoRead) { super.setAutoRead(autoRead); @@ -225,8 +232,14 @@ final class AioServerSocketChannelConfig extends DefaultChannelConfig implements } @Override - public ServerSocketChannelConfig setDefaultHandlerByteBufType(ChannelHandlerByteBufType type) { - super.setDefaultHandlerByteBufType(type); + public AioServerSocketChannelConfig setWriteBufferLowWaterMark(int writeBufferLowWaterMark) { + super.setWriteBufferLowWaterMark(writeBufferLowWaterMark); + return this; + } + + @Override + public AioServerSocketChannelConfig setWriteBufferHighWaterMark(int writeBufferHighWaterMark) { + super.setWriteBufferHighWaterMark(writeBufferHighWaterMark); return this; } } diff --git a/transport/src/main/java/io/netty/channel/socket/aio/AioSocketChannel.java b/transport/src/main/java/io/netty/channel/socket/aio/AioSocketChannel.java index 42fceac50f..4c00360790 100755 --- a/transport/src/main/java/io/netty/channel/socket/aio/AioSocketChannel.java +++ b/transport/src/main/java/io/netty/channel/socket/aio/AioSocketChannel.java @@ -15,22 +15,22 @@ */ package io.netty.channel.socket.aio; -import io.netty.buffer.BufType; import io.netty.buffer.ByteBuf; -import io.netty.channel.Channel; import io.netty.channel.ChannelException; -import io.netty.channel.ChannelFlushPromiseNotifier; import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelMetadata; import io.netty.channel.ChannelPipeline; import io.netty.channel.ChannelPromise; import io.netty.channel.EventLoop; +import io.netty.channel.FileRegion; +import io.netty.channel.MessageList; import io.netty.channel.aio.AbstractAioChannel; import io.netty.channel.aio.AioCompletionHandler; import io.netty.channel.aio.AioEventLoopGroup; import io.netty.channel.socket.ChannelInputShutdownEvent; import io.netty.channel.socket.ServerSocketChannel; import io.netty.channel.socket.SocketChannel; +import io.netty.util.internal.PlatformDependent; import java.io.IOException; import java.net.InetSocketAddress; @@ -52,13 +52,13 @@ import java.util.concurrent.TimeUnit; */ public class AioSocketChannel extends AbstractAioChannel implements SocketChannel { - private static final ChannelMetadata METADATA = new ChannelMetadata(BufType.BYTE, false); + private static final ChannelMetadata METADATA = new ChannelMetadata(false); - private static final CompletionHandler CONNECT_HANDLER = new ConnectHandler(); - private static final CompletionHandler WRITE_HANDLER = new WriteHandler(); - private static final CompletionHandler READ_HANDLER = new ReadHandler(); - private static final CompletionHandler GATHERING_WRITE_HANDLER = new WriteHandler(); - private static final CompletionHandler SCATTERING_READ_HANDLER = new ReadHandler(); + private final CompletionHandler connectHandler = new ConnectHandler(this); + private final CompletionHandler writeHandler = new WriteHandler(this); + private final CompletionHandler readHandler = new ReadHandler(this); + private final CompletionHandler gatheringWriteHandler = new WriteHandler(this); + private final CompletionHandler scatteringReadHandler = new ReadHandler(this); private static AsynchronousSocketChannel newSocket(AsynchronousChannelGroup group) { try { @@ -76,12 +76,10 @@ public class AioSocketChannel extends AbstractAioChannel implements SocketChanne private boolean inDoBeginRead; private boolean readAgain; - private static final int NO_WRITE_IN_PROGRESS = 0; - private static final int WRITE_IN_PROGRESS = 1; - private static final int WRITE_FAILED = -2; - - private int writeInProgress; - private boolean inDoFlushByteBuffer; + private Throwable writeException; + private boolean writeInProgress; + private boolean inDoWrite; + private boolean fileRegionDone; /** * Create a new instance which has not yet attached an {@link AsynchronousSocketChannel}. The @@ -188,7 +186,7 @@ public class AioSocketChannel extends AbstractAioChannel implements SocketChanne } } - javaChannel().connect(remoteAddress, this, CONNECT_HANDLER); + javaChannel().connect(remoteAddress, null, connectHandler); } @Override @@ -249,72 +247,99 @@ public class AioSocketChannel extends AbstractAioChannel implements SocketChanne } @Override - protected void doFlushByteBuffer(ByteBuf buf) throws Exception { - if (inDoFlushByteBuffer || writeInProgress != NO_WRITE_IN_PROGRESS) { - return; + protected int doWrite(MessageList msgs, int index) throws Exception { + if (inDoWrite || writeInProgress) { + return 0; } - - inDoFlushByteBuffer = true; + inDoWrite = true; try { - if (buf.isReadable()) { - for (;;) { - if (buf.refCnt() == 0) { - break; - } - // Ensure the readerIndex of the buffer is 0 before beginning an async write. - // Otherwise, JDK can write into a wrong region of the buffer when a handler calls - // discardReadBytes() later, modifying the readerIndex and the writerIndex unexpectedly. - buf.discardReadBytes(); - - writeInProgress = WRITE_IN_PROGRESS; - if (buf.nioBufferCount() == 1) { - javaChannel().write( - buf.nioBuffer(), config.getWriteTimeout(), TimeUnit.MILLISECONDS, this, WRITE_HANDLER); - } else { - ByteBuffer[] buffers = buf.nioBuffers(buf.readerIndex(), buf.readableBytes()); - if (buffers.length == 1) { - javaChannel().write( - buffers[0], config.getWriteTimeout(), TimeUnit.MILLISECONDS, this, WRITE_HANDLER); - } else { - javaChannel().write( - buffers, 0, buffers.length, config.getWriteTimeout(), TimeUnit.MILLISECONDS, - this, GATHERING_WRITE_HANDLER); - } - } - - if (writeInProgress != NO_WRITE_IN_PROGRESS) { - if (writeInProgress == WRITE_FAILED) { - // failed because of an exception so reset state and break out of the loop now - // See #1242 - writeInProgress = NO_WRITE_IN_PROGRESS; - break; - } - // JDK decided to write data (or notify handler) later. - buf.suspendIntermediaryDeallocations(); - break; - } - - // JDK performed the write operation immediately and notified the handler. - // We know this because we set asyncWriteInProgress to false in the handler. - if (!buf.isReadable()) { - // There's nothing left in the buffer. No need to retry writing. - break; - } - - // There's more to write. Continue the loop. + Object msg = msgs.get(index); + if (msg instanceof ByteBuf) { + if (doWriteBuffer((ByteBuf) msg)) { + return 1; } - } else { - flushFutureNotifier.notifyFlushFutures(); + return 0; + } + if (msg instanceof FileRegion) { + if (doWriteFileRegion((FileRegion) msg)) { + return 1; + } + return 0; } } finally { - inDoFlushByteBuffer = false; + inDoWrite = false; } + return 0; } - @Override - protected void doFlushFileRegion(FlushTask task) throws Exception { - task.region().transferTo(new WritableByteChannelAdapter(task), 0); + private boolean doWriteBuffer(ByteBuf buf) throws Exception { + if (buf.isReadable()) { + for (;;) { + checkWriteException(); + writeInProgress = true; + if (buf.nioBufferCount() == 1) { + javaChannel().write( + buf.nioBuffer(), config.getWriteTimeout(), TimeUnit.MILLISECONDS, + buf, writeHandler); + } else { + ByteBuffer[] buffers = buf.nioBuffers(buf.readerIndex(), buf.readableBytes()); + if (buffers.length == 1) { + javaChannel().write( + buffers[0], config.getWriteTimeout(), TimeUnit.MILLISECONDS, buf, writeHandler); + } else { + javaChannel().write( + buffers, 0, buffers.length, config.getWriteTimeout(), TimeUnit.MILLISECONDS, + buf, gatheringWriteHandler); + } + } + + if (writeInProgress) { + // JDK decided to write data (or notify handler) later. + return false; + } + checkWriteException(); + + // JDK performed the write operation immediately and notified the handler. + // We know this because we set asyncWriteInProgress to false in the handler. + if (!buf.isReadable()) { + // There's nothing left in the buffer. No need to retry writing. + return true; + } + + // There's more to write. Continue the loop. + } + } + return true; + } + + private boolean doWriteFileRegion(FileRegion region) throws Exception { + checkWriteException(); + + if (fileRegionDone) { + // fileregion was complete in the CompletionHandler + fileRegionDone = false; + // was written complete + return true; + } + + WritableByteChannelAdapter byteChannel = new WritableByteChannelAdapter(region); + region.transferTo(byteChannel, 0); + + // check if the FileRegion is already complete. This may be the case if all could be written directly + if (byteChannel.written >= region.count()) { + return true; + } + return false; + } + + private void checkWriteException() throws Exception { + if (writeException != null) { + fileRegionDone = false; + Throwable e = writeException; + writeException = null; + PlatformDependent.throwException(e); + } } @Override @@ -335,31 +360,23 @@ public class AioSocketChannel extends AbstractAioChannel implements SocketChanne break; } - ByteBuf byteBuf = pipeline().inboundByteBuffer(); - - // Ensure the readerIndex of the buffer is 0 before beginning an async read. - // Otherwise, JDK can read into a wrong region of the buffer when a handler calls - // discardReadBytes() later, modifying the readerIndex and the writerIndex unexpectedly. - // See https://github.com/netty/netty/issues/1377 - byteBuf.discardReadBytes(); - - expandReadBuffer(byteBuf); + ByteBuf byteBuf = alloc().buffer(); readInProgress = true; if (byteBuf.nioBufferCount() == 1) { // Get a ByteBuffer view on the ByteBuf ByteBuffer buffer = byteBuf.nioBuffer(byteBuf.writerIndex(), byteBuf.writableBytes()); javaChannel().read( - buffer, config.getReadTimeout(), TimeUnit.MILLISECONDS, this, READ_HANDLER); + buffer, config.getReadTimeout(), TimeUnit.MILLISECONDS, byteBuf, readHandler); } else { ByteBuffer[] buffers = byteBuf.nioBuffers(byteBuf.writerIndex(), byteBuf.writableBytes()); if (buffers.length == 1) { javaChannel().read( - buffers[0], config.getReadTimeout(), TimeUnit.MILLISECONDS, this, READ_HANDLER); + buffers[0], config.getReadTimeout(), TimeUnit.MILLISECONDS, byteBuf, readHandler); } else { javaChannel().read( buffers, 0, buffers.length, config.getReadTimeout(), TimeUnit.MILLISECONDS, - this, SCATTERING_READ_HANDLER); + byteBuf, scatteringReadHandler); } } @@ -381,51 +398,53 @@ public class AioSocketChannel extends AbstractAioChannel implements SocketChanne } } - private static final class WriteHandler extends AioCompletionHandler { + private void setWriteException(Throwable cause) { + writeException = cause; + } + + private static final class WriteHandler + extends AioCompletionHandler { + + WriteHandler(AioSocketChannel channel) { + super(channel); + } @Override - protected void completed0(T result, AioSocketChannel channel) { - channel.writeInProgress = NO_WRITE_IN_PROGRESS; + protected void completed0(AioSocketChannel channel, T result, ByteBuf buf) { + channel.writeException = null; + channel.writeInProgress = false; + boolean release = true; + try { + int writtenBytes = result.intValue(); + if (writtenBytes > 0) { + // Update the readerIndex with the amount of read bytes + buf.readerIndex(buf.readerIndex() + writtenBytes); + } + if (buf.isReadable()) { + // something left in the buffer so not release it + release = false; + } + } finally { + if (release) { + buf.release(); + } - ByteBuf buf = channel.unsafe().headContext().outboundByteBuffer(); - if (buf.refCnt() == 0) { - return; - } - - buf.resumeIntermediaryDeallocations(); - - int writtenBytes = result.intValue(); - if (writtenBytes > 0) { - // Update the readerIndex with the amount of read bytes - buf.readerIndex(buf.readerIndex() + writtenBytes); - } - - if (channel.inDoFlushByteBuffer) { - // JDK performed the write operation immediately and notified this handler immediately. - // doFlushByteBuffer() will do subsequent write operations if necessary for us. - return; - } - - // Update the write counter and notify flush futures only when the handler is called outside of - // unsafe().flushNow() because flushNow() will do that for us. - ChannelFlushPromiseNotifier notifier = channel.flushFutureNotifier; - notifier.increaseWriteCounter(writtenBytes); - notifier.notifyFlushFutures(); - - // Stop flushing if disconnected. - if (!channel.isActive()) { - return; - } - - if (buf.isReadable()) { - channel.unsafe().flushNow(); + if (channel.inDoWrite) { + // JDK performed the write operation immediately and notified this handler immediately. + // doWrite(...) will do subsequent write operations if necessary for us. + } else { + // trigger flush so doWrite(..) is called again. This will either trigger a new write to the + // channel or remove the empty bytebuf (which was written completely before) from the MessageList. + channel.unsafe().flushNow(); + } } } @Override - protected void failed0(Throwable cause, AioSocketChannel channel) { - channel.writeInProgress = WRITE_FAILED; - channel.flushFutureNotifier.notifyFlushFutures(cause); + protected void failed0(AioSocketChannel channel, Throwable cause, ByteBuf buf) { + buf.release(); + channel.setWriteException(cause); + channel.writeInProgress = false; // Check if the exception was raised because of an InterruptedByTimeoutException which means that the // write timeout was hit. In that case we should close the channel as it may be unusable anyway. @@ -434,13 +453,23 @@ public class AioSocketChannel extends AbstractAioChannel implements SocketChanne if (cause instanceof InterruptedByTimeoutException) { channel.unsafe().close(channel.unsafe().voidPromise()); } + + if (!channel.inDoWrite) { + // trigger flushNow() so the Throwable is thrown in doWrite(...). This will make sure that all + // queued MessageLists are failed. + channel.unsafe().flushNow(); + } } } - private static final class ReadHandler extends AioCompletionHandler { + private final class ReadHandler extends AioCompletionHandler { + + ReadHandler(AioSocketChannel channel) { + super(channel); + } @Override - protected void completed0(T result, AioSocketChannel channel) { + protected void completed0(AioSocketChannel channel, T result, ByteBuf byteBuf) { channel.readInProgress = false; if (channel.inputShutdown) { @@ -449,61 +478,71 @@ public class AioSocketChannel extends AbstractAioChannel implements SocketChanne return; } + boolean release = true; final ChannelPipeline pipeline = channel.pipeline(); - final ByteBuf byteBuf = pipeline.inboundByteBuffer(); - - boolean closed = false; - boolean read = false; - boolean firedChannelReadSuspended = false; try { - int localReadAmount = result.intValue(); - if (localReadAmount > 0) { - // Set the writerIndex of the buffer correctly to the - // current writerIndex + read amount of bytes. - // - // This is needed as the ByteBuffer and the ByteBuf does not share - // each others index - byteBuf.writerIndex(byteBuf.writerIndex() + localReadAmount); + boolean closed = false; + boolean read = false; + boolean firedChannelReadSuspended = false; + try { + int localReadAmount = result.intValue(); + if (localReadAmount > 0) { + // Set the writerIndex of the buffer correctly to the + // current writerIndex + read amount of bytes. + // + // This is needed as the ByteBuffer and the ByteBuf does not share + // each others index + byteBuf.writerIndex(byteBuf.writerIndex() + localReadAmount); - read = true; - } else if (localReadAmount < 0) { - closed = true; - } - } catch (Throwable t) { - if (read) { - read = false; - pipeline.fireInboundBufferUpdated(); - } - - if (!closed && channel.isOpen()) { - firedChannelReadSuspended = true; - pipeline.fireChannelReadSuspended(); - } - - pipeline.fireExceptionCaught(t); - } finally { - if (read) { - pipeline.fireInboundBufferUpdated(); - } - - // Double check because fireInboundBufferUpdated() might have triggered the closure by a user handler. - if (closed || !channel.isOpen()) { - channel.inputShutdown = true; - if (channel.isOpen()) { - if (channel.config().isAllowHalfClosure()) { - pipeline.fireUserEventTriggered(ChannelInputShutdownEvent.INSTANCE); - } else { - channel.unsafe().close(channel.unsafe().voidPromise()); - } + read = true; + } else if (localReadAmount < 0) { + closed = true; } - } else if (!firedChannelReadSuspended) { - pipeline.fireChannelReadSuspended(); + } catch (Throwable t) { + if (read) { + read = false; + release = false; + pipeline.fireMessageReceived(byteBuf); + } + + if (!closed && isOpen()) { + firedChannelReadSuspended = true; + pipeline.fireChannelReadSuspended(); + } + + pipeline.fireExceptionCaught(t); + } finally { + if (read) { + release = false; + pipeline.fireMessageReceived(byteBuf); + } + + // Double check because fireInboundBufferUpdated() might have triggered + // the closure by a user handler. + if (closed || !channel.isOpen()) { + channel.inputShutdown = true; + if (isOpen()) { + if (channel.config().isAllowHalfClosure()) { + pipeline.fireUserEventTriggered(ChannelInputShutdownEvent.INSTANCE); + } else { + channel.unsafe().close(channel.unsafe().voidPromise()); + } + } + } else if (!firedChannelReadSuspended) { + pipeline.fireChannelReadSuspended(); + } + } + } finally { + if (release) { + byteBuf.release(); } } } @Override - protected void failed0(Throwable t, AioSocketChannel channel) { + protected void failed0(AioSocketChannel channel, Throwable t, ByteBuf buf) { + buf.release(); + channel.readInProgress = false; if (t instanceof ClosedChannelException) { channel.inputShutdown = true; @@ -522,15 +561,18 @@ public class AioSocketChannel extends AbstractAioChannel implements SocketChanne } } - private static final class ConnectHandler extends AioCompletionHandler { + private static final class ConnectHandler extends AioCompletionHandler { + ConnectHandler(AioSocketChannel channel) { + super(channel); + } @Override - protected void completed0(Void result, AioSocketChannel channel) { + protected void completed0(AioSocketChannel channel, Void result, Void attachment) { ((DefaultAioUnsafe) channel.unsafe()).connectSuccess(); } @Override - protected void failed0(Throwable exc, AioSocketChannel channel) { + protected void failed0(AioSocketChannel channel, Throwable exc, Void attachment) { ((DefaultAioUnsafe) channel.unsafe()).connectFailed(exc); } } @@ -541,52 +583,17 @@ public class AioSocketChannel extends AbstractAioChannel implements SocketChanne } private final class WritableByteChannelAdapter implements WritableByteChannel { - private final FlushTask task; + private final FileRegionWriteHandler handler = new FileRegionWriteHandler(); + private final FileRegion region; private long written; - public WritableByteChannelAdapter(FlushTask task) { - this.task = task; + public WritableByteChannelAdapter(FileRegion region) { + this.region = region; } @Override public int write(final ByteBuffer src) { - javaChannel().write(src, AioSocketChannel.this, new AioCompletionHandler() { - - @Override - public void completed0(Integer result, Channel attachment) { - try { - if (result == 0) { - javaChannel().write(src, AioSocketChannel.this, this); - return; - } - if (result == -1) { - checkEOF(task.region(), written); - task.setSuccess(); - return; - } - written += result; - - task.setProgress(written); - - if (written >= task.region().count()) { - task.setSuccess(); - return; - } - if (src.hasRemaining()) { - javaChannel().write(src, AioSocketChannel.this, this); - } else { - task.region().transferTo(WritableByteChannelAdapter.this, written); - } - } catch (Throwable cause) { - task.setFailure(cause); - } - } - - @Override - public void failed0(Throwable exc, Channel attachment) { - task.setFailure(exc); - } - }); + javaChannel().write(src, src, handler); return 0; } @@ -599,6 +606,62 @@ public class AioSocketChannel extends AbstractAioChannel implements SocketChanne public void close() throws IOException { javaChannel().close(); } - } + private final class FileRegionWriteHandler extends AioCompletionHandler { + + FileRegionWriteHandler() { + super(AioSocketChannel.this); + } + + @Override + public void completed0(AioSocketChannel channel, Integer result, ByteBuffer src) { + try { + assert !fileRegionDone; + + if (result == -1) { + checkEOF(region); + // mark the region as done and release it + fileRegionDone = true; + region.release(); + return; + } + + written += result; + + if (written >= region.count()) { + channel.writeInProgress = false; + + // mark the region as done and release it + fileRegionDone = true; + region.release(); + return; + } + if (src.hasRemaining()) { + // something left in the buffer trigger a write again + javaChannel().write(src, src, this); + } else { + // everything was written out of the src buffer, so trigger a new transfer with new data + region.transferTo(WritableByteChannelAdapter.this, written); + } + } catch (Throwable cause) { + failed0(channel, cause, src); + } + } + + @Override + public void failed0(AioSocketChannel channel, Throwable cause, ByteBuffer src) { + assert !fileRegionDone; + + // mark the region as done and release it + fileRegionDone = true; + region.release(); + channel.setWriteException(cause); + if (!inDoWrite) { + // not executed as part of the doWrite(...) so trigger flushNow() to make sure the doWrite(...) + // will be called again and so rethrow the exception + channel.unsafe().flushNow(); + } + } + } + } } diff --git a/transport/src/main/java/io/netty/channel/socket/aio/AioSocketChannelConfig.java b/transport/src/main/java/io/netty/channel/socket/aio/AioSocketChannelConfig.java index 951e1f9093..c9878eda31 100644 --- a/transport/src/main/java/io/netty/channel/socket/aio/AioSocketChannelConfig.java +++ b/transport/src/main/java/io/netty/channel/socket/aio/AioSocketChannelConfig.java @@ -17,6 +17,7 @@ package io.netty.channel.socket.aio; import io.netty.buffer.ByteBufAllocator; import io.netty.channel.ChannelOption; +import io.netty.channel.RecvByteBufAllocator; import io.netty.channel.socket.SocketChannelConfig; import java.nio.channels.InterruptedByTimeoutException; @@ -110,8 +111,8 @@ public interface AioSocketChannelConfig extends SocketChannelConfig { AioSocketChannelConfig setAllocator(ByteBufAllocator allocator); @Override - AioSocketChannelConfig setAutoRead(boolean autoRead); + AioSocketChannelConfig setRecvByteBufAllocator(RecvByteBufAllocator allocator); @Override - AioSocketChannelConfig setDefaultHandlerByteBufType(ChannelHandlerByteBufType type); + AioSocketChannelConfig setAutoRead(boolean autoRead); } diff --git a/transport/src/main/java/io/netty/channel/socket/aio/DefaultAioSocketChannelConfig.java b/transport/src/main/java/io/netty/channel/socket/aio/DefaultAioSocketChannelConfig.java index 1f88dc78d5..6c75e741a9 100644 --- a/transport/src/main/java/io/netty/channel/socket/aio/DefaultAioSocketChannelConfig.java +++ b/transport/src/main/java/io/netty/channel/socket/aio/DefaultAioSocketChannelConfig.java @@ -19,6 +19,7 @@ import io.netty.buffer.ByteBufAllocator; import io.netty.channel.ChannelException; import io.netty.channel.ChannelOption; import io.netty.channel.DefaultChannelConfig; +import io.netty.channel.RecvByteBufAllocator; import io.netty.util.internal.PlatformDependent; import java.io.IOException; @@ -352,13 +353,24 @@ final class DefaultAioSocketChannelConfig extends DefaultChannelConfig return (AioSocketChannelConfig) super.setAllocator(allocator); } + @Override + public AioSocketChannelConfig setRecvByteBufAllocator(RecvByteBufAllocator allocator) { + super.setRecvByteBufAllocator(allocator); + return this; + } + @Override public AioSocketChannelConfig setAutoRead(boolean autoRead) { return (AioSocketChannelConfig) super.setAutoRead(autoRead); } @Override - public AioSocketChannelConfig setDefaultHandlerByteBufType(ChannelHandlerByteBufType type) { - return (AioSocketChannelConfig) super.setDefaultHandlerByteBufType(type); + public AioSocketChannelConfig setWriteBufferLowWaterMark(int writeBufferLowWaterMark) { + return (AioSocketChannelConfig) super.setWriteBufferLowWaterMark(writeBufferLowWaterMark); + } + + @Override + public AioSocketChannelConfig setWriteBufferHighWaterMark(int writeBufferHighWaterMark) { + return (AioSocketChannelConfig) super.setWriteBufferHighWaterMark(writeBufferHighWaterMark); } } diff --git a/transport/src/main/java/io/netty/channel/socket/nio/NioDatagramChannel.java b/transport/src/main/java/io/netty/channel/socket/nio/NioDatagramChannel.java index 3c0072d704..def2ea368a 100755 --- a/transport/src/main/java/io/netty/channel/socket/nio/NioDatagramChannel.java +++ b/transport/src/main/java/io/netty/channel/socket/nio/NioDatagramChannel.java @@ -15,17 +15,17 @@ */ package io.netty.channel.socket.nio; -import io.netty.buffer.BufType; -import io.netty.buffer.BufUtil; import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBufHolder; -import io.netty.buffer.MessageBuf; +import io.netty.buffer.ByteBufUtil; import io.netty.channel.AddressedEnvelope; import io.netty.channel.Channel; import io.netty.channel.ChannelException; import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelMetadata; import io.netty.channel.ChannelPromise; +import io.netty.channel.MessageList; +import io.netty.channel.RecvByteBufAllocator; import io.netty.channel.nio.AbstractNioMessageChannel; import io.netty.channel.socket.DatagramChannelConfig; import io.netty.channel.socket.DatagramPacket; @@ -59,12 +59,14 @@ import java.util.Map; public final class NioDatagramChannel extends AbstractNioMessageChannel implements io.netty.channel.socket.DatagramChannel { - private static final ChannelMetadata METADATA = new ChannelMetadata(BufType.MESSAGE, true); + private static final ChannelMetadata METADATA = new ChannelMetadata(true); private final DatagramChannelConfig config; private final Map> memberships = new HashMap>(); + private RecvByteBufAllocator.Handle allocHandle; + private static DatagramChannel newSocket() { try { return DatagramChannel.open(); @@ -198,9 +200,14 @@ public final class NioDatagramChannel } @Override - protected int doReadMessages(MessageBuf buf) throws Exception { + protected int doReadMessages(MessageList buf) throws Exception { DatagramChannel ch = javaChannel(); - ByteBuf data = alloc().directBuffer(config().getReceivePacketSize()); + DatagramChannelConfig config = config(); + RecvByteBufAllocator.Handle allocHandle = this.allocHandle; + if (allocHandle == null) { + this.allocHandle = allocHandle = config.getRecvByteBufAllocator().newHandle(); + } + ByteBuf data = allocHandle.allocate(config.getAllocator()); boolean free = true; try { ByteBuffer nioData = data.nioBuffer(data.writerIndex(), data.writableBytes()); @@ -210,7 +217,10 @@ public final class NioDatagramChannel return 0; } - data.writerIndex(data.writerIndex() + nioData.position()); + int readBytes = nioData.position(); + data.writerIndex(data.writerIndex() + readBytes); + allocHandle.record(readBytes); + buf.add(new DatagramPacket(data, localAddress(), remoteAddress)); free = false; return 1; @@ -225,8 +235,8 @@ public final class NioDatagramChannel } @Override - protected int doWriteMessages(MessageBuf buf, boolean lastSpin) throws Exception { - final Object o = buf.peek(); + protected int doWriteMessages(MessageList msgs, int index, boolean lastSpin) throws Exception { + final Object o = msgs.get(index); final Object m; final ByteBuf data; final SocketAddress remoteAddress; @@ -245,7 +255,7 @@ public final class NioDatagramChannel } else if (m instanceof ByteBuf) { data = (ByteBuf) m; } else { - BufUtil.release(buf.remove()); + ByteBufUtil.release(o); throw new ChannelException("unsupported message type: " + StringUtil.simpleClassName(o)); } @@ -283,9 +293,9 @@ public final class NioDatagramChannel } // Wrote a packet - free the message. - BufUtil.release(buf.remove()); + ByteBufUtil.release(o); - if (buf.isEmpty()) { + if (index + 1 == msgs.size()) { // Wrote the outbound buffer completely - clear OP_WRITE. if ((interestOps & SelectionKey.OP_WRITE) != 0) { key.interestOps(interestOps & ~SelectionKey.OP_WRITE); diff --git a/transport/src/main/java/io/netty/channel/socket/nio/NioServerSocketChannel.java b/transport/src/main/java/io/netty/channel/socket/nio/NioServerSocketChannel.java index b9028a70d1..72e8b7eac9 100755 --- a/transport/src/main/java/io/netty/channel/socket/nio/NioServerSocketChannel.java +++ b/transport/src/main/java/io/netty/channel/socket/nio/NioServerSocketChannel.java @@ -15,10 +15,9 @@ */ package io.netty.channel.socket.nio; -import io.netty.buffer.BufType; -import io.netty.buffer.MessageBuf; import io.netty.channel.ChannelException; import io.netty.channel.ChannelMetadata; +import io.netty.channel.MessageList; import io.netty.channel.nio.AbstractNioMessageChannel; import io.netty.channel.socket.DefaultServerSocketChannelConfig; import io.netty.channel.socket.ServerSocketChannelConfig; @@ -39,7 +38,7 @@ import java.nio.channels.SocketChannel; public class NioServerSocketChannel extends AbstractNioMessageChannel implements io.netty.channel.socket.ServerSocketChannel { - private static final ChannelMetadata METADATA = new ChannelMetadata(BufType.MESSAGE, false); + private static final ChannelMetadata METADATA = new ChannelMetadata(false); private static final InternalLogger logger = InternalLoggerFactory.getInstance(NioServerSocketChannel.class); @@ -108,7 +107,7 @@ public class NioServerSocketChannel extends AbstractNioMessageChannel } @Override - protected int doReadMessages(MessageBuf buf) throws Exception { + protected int doReadMessages(MessageList buf) throws Exception { SocketChannel ch = javaChannel().accept(); try { @@ -152,7 +151,7 @@ public class NioServerSocketChannel extends AbstractNioMessageChannel } @Override - protected int doWriteMessages(MessageBuf buf, boolean lastSpin) throws Exception { + protected int doWriteMessages(MessageList msgs, int index, boolean lastSpin) throws Exception { throw new UnsupportedOperationException(); } } diff --git a/transport/src/main/java/io/netty/channel/socket/nio/NioSocketChannel.java b/transport/src/main/java/io/netty/channel/socket/nio/NioSocketChannel.java index 1d4483064c..240b8cb3b1 100755 --- a/transport/src/main/java/io/netty/channel/socket/nio/NioSocketChannel.java +++ b/transport/src/main/java/io/netty/channel/socket/nio/NioSocketChannel.java @@ -15,7 +15,6 @@ */ package io.netty.channel.socket.nio; -import io.netty.buffer.BufType; import io.netty.buffer.ByteBuf; import io.netty.channel.Channel; import io.netty.channel.ChannelException; @@ -23,6 +22,7 @@ import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelMetadata; import io.netty.channel.ChannelPromise; import io.netty.channel.EventLoop; +import io.netty.channel.FileRegion; import io.netty.channel.nio.AbstractNioByteChannel; import io.netty.channel.socket.DefaultSocketChannelConfig; import io.netty.channel.socket.ServerSocketChannel; @@ -35,13 +35,14 @@ import java.net.InetSocketAddress; import java.net.SocketAddress; import java.nio.channels.SelectionKey; import java.nio.channels.SocketChannel; +import java.nio.channels.WritableByteChannel; /** * {@link io.netty.channel.socket.SocketChannel} which uses NIO selector based implementation. */ public class NioSocketChannel extends AbstractNioByteChannel implements io.netty.channel.socket.SocketChannel { - private static final ChannelMetadata METADATA = new ChannelMetadata(BufType.BYTE, false); + private static final ChannelMetadata METADATA = new ChannelMetadata(false); private static final InternalLogger logger = InternalLoggerFactory.getInstance(NioSocketChannel.class); @@ -258,4 +259,34 @@ public class NioSocketChannel extends AbstractNioByteChannel implements io.netty return writtenBytes; } + + @Override + protected long doWriteFileRegion(FileRegion region, boolean lastSpin) throws Exception { + if (javaChannel() instanceof WritableByteChannel) { + WritableByteChannel wch = javaChannel(); + long localWrittenBytes = region.transferTo(wch, region.transfered()); + if (localWrittenBytes > 0 || lastSpin) { + // check if the region was written complete. If not set OP_WRITE so the eventloop + // will write the rest once writable again + if (region.transfered() < region.count()) { + final SelectionKey key = selectionKey(); + final int interestOps = key.interestOps(); + if ((interestOps & SelectionKey.OP_WRITE) == 0) { + key.interestOps(interestOps | SelectionKey.OP_WRITE); + } + } + } else { + final SelectionKey key = selectionKey(); + final int interestOps = key.interestOps(); + // Wrote the region completely - clear OP_WRITE. + if ((interestOps & SelectionKey.OP_WRITE) != 0) { + key.interestOps(interestOps & ~SelectionKey.OP_WRITE); + } + } + return localWrittenBytes; + } else { + throw new UnsupportedOperationException("Underlying Channel is not of instance " + + WritableByteChannel.class); + } + } } diff --git a/transport/src/main/java/io/netty/channel/socket/oio/DefaultOioServerSocketChannelConfig.java b/transport/src/main/java/io/netty/channel/socket/oio/DefaultOioServerSocketChannelConfig.java index 99370e4b86..223ad2a513 100644 --- a/transport/src/main/java/io/netty/channel/socket/oio/DefaultOioServerSocketChannelConfig.java +++ b/transport/src/main/java/io/netty/channel/socket/oio/DefaultOioServerSocketChannelConfig.java @@ -18,6 +18,7 @@ package io.netty.channel.socket.oio; import io.netty.buffer.ByteBufAllocator; import io.netty.channel.ChannelException; import io.netty.channel.ChannelOption; +import io.netty.channel.RecvByteBufAllocator; import io.netty.channel.socket.DefaultServerSocketChannelConfig; import io.netty.channel.socket.ServerSocketChannel; @@ -126,14 +127,14 @@ public class DefaultOioServerSocketChannelConfig extends DefaultServerSocketChan } @Override - public OioServerSocketChannelConfig setAutoRead(boolean autoRead) { - super.setAutoRead(autoRead); + public OioServerSocketChannelConfig setRecvByteBufAllocator(RecvByteBufAllocator allocator) { + super.setRecvByteBufAllocator(allocator); return this; } @Override - public OioServerSocketChannelConfig setDefaultHandlerByteBufType(ChannelHandlerByteBufType type) { - super.setDefaultHandlerByteBufType(type); + public OioServerSocketChannelConfig setAutoRead(boolean autoRead) { + super.setAutoRead(autoRead); return this; } } diff --git a/transport/src/main/java/io/netty/channel/socket/oio/DefaultOioSocketChannelConfig.java b/transport/src/main/java/io/netty/channel/socket/oio/DefaultOioSocketChannelConfig.java index f0d4472d13..5c4f6df25b 100644 --- a/transport/src/main/java/io/netty/channel/socket/oio/DefaultOioSocketChannelConfig.java +++ b/transport/src/main/java/io/netty/channel/socket/oio/DefaultOioSocketChannelConfig.java @@ -18,6 +18,7 @@ package io.netty.channel.socket.oio; import io.netty.buffer.ByteBufAllocator; import io.netty.channel.ChannelException; import io.netty.channel.ChannelOption; +import io.netty.channel.RecvByteBufAllocator; import io.netty.channel.socket.DefaultSocketChannelConfig; import io.netty.channel.socket.SocketChannel; @@ -154,14 +155,14 @@ public class DefaultOioSocketChannelConfig extends DefaultSocketChannelConfig im } @Override - public OioSocketChannelConfig setAutoRead(boolean autoRead) { - super.setAutoRead(autoRead); + public OioSocketChannelConfig setRecvByteBufAllocator(RecvByteBufAllocator allocator) { + super.setRecvByteBufAllocator(allocator); return this; } @Override - public OioSocketChannelConfig setDefaultHandlerByteBufType(ChannelHandlerByteBufType type) { - super.setDefaultHandlerByteBufType(type); + public OioSocketChannelConfig setAutoRead(boolean autoRead) { + super.setAutoRead(autoRead); return this; } } diff --git a/transport/src/main/java/io/netty/channel/socket/oio/OioDatagramChannel.java b/transport/src/main/java/io/netty/channel/socket/oio/OioDatagramChannel.java index f1c7605ae5..1d329105e7 100755 --- a/transport/src/main/java/io/netty/channel/socket/oio/OioDatagramChannel.java +++ b/transport/src/main/java/io/netty/channel/socket/oio/OioDatagramChannel.java @@ -15,17 +15,17 @@ */ package io.netty.channel.socket.oio; -import io.netty.buffer.BufType; -import io.netty.buffer.BufUtil; import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBufHolder; -import io.netty.buffer.MessageBuf; +import io.netty.buffer.ByteBufUtil; import io.netty.channel.AddressedEnvelope; import io.netty.channel.Channel; import io.netty.channel.ChannelException; import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelMetadata; import io.netty.channel.ChannelPromise; +import io.netty.channel.MessageList; +import io.netty.channel.RecvByteBufAllocator; import io.netty.channel.oio.AbstractOioMessageChannel; import io.netty.channel.socket.DatagramChannel; import io.netty.channel.socket.DatagramChannelConfig; @@ -59,12 +59,14 @@ public class OioDatagramChannel extends AbstractOioMessageChannel private static final InternalLogger logger = InternalLoggerFactory.getInstance(OioDatagramChannel.class); - private static final ChannelMetadata METADATA = new ChannelMetadata(BufType.MESSAGE, true); + private static final ChannelMetadata METADATA = new ChannelMetadata(true); private final MulticastSocket socket; private final DatagramChannelConfig config; private final java.net.DatagramPacket tmpPacket = new java.net.DatagramPacket(EmptyArrays.EMPTY_BYTES, 0); + private RecvByteBufAllocator.Handle allocHandle; + private static MulticastSocket newSocket() { try { return new MulticastSocket(null); @@ -199,13 +201,17 @@ public class OioDatagramChannel extends AbstractOioMessageChannel } @Override - protected int doReadMessages(MessageBuf buf) throws Exception { - int packetSize = config().getReceivePacketSize(); - ByteBuf data = alloc().heapBuffer(packetSize); - boolean free = true; + protected int doReadMessages(MessageList buf) throws Exception { + DatagramChannelConfig config = config(); + RecvByteBufAllocator.Handle allocHandle = this.allocHandle; + if (allocHandle == null) { + this.allocHandle = allocHandle = config.getRecvByteBufAllocator().newHandle(); + } + ByteBuf data = config.getAllocator().heapBuffer(allocHandle.guess()); + boolean free = true; try { - tmpPacket.setData(data.array(), data.arrayOffset(), packetSize); + tmpPacket.setData(data.array(), data.arrayOffset(), data.capacity()); socket.receive(tmpPacket); InetSocketAddress remoteAddr = (InetSocketAddress) tmpPacket.getSocketAddress(); @@ -213,7 +219,9 @@ public class OioDatagramChannel extends AbstractOioMessageChannel remoteAddr = remoteAddress(); } - buf.add(new DatagramPacket(data.writerIndex(tmpPacket.getLength()), localAddress(), remoteAddr)); + int readBytes = tmpPacket.getLength(); + allocHandle.record(readBytes); + buf.add(new DatagramPacket(data.writerIndex(readBytes), localAddress(), remoteAddr)); free = false; return 1; } catch (SocketTimeoutException e) { @@ -235,8 +243,8 @@ public class OioDatagramChannel extends AbstractOioMessageChannel } @Override - protected void doWriteMessages(MessageBuf buf) throws Exception { - final Object o = buf.poll(); + protected int doWrite(MessageList msgs, int index) throws Exception { + final Object o = msgs.get(index); final Object m; final ByteBuf data; final SocketAddress remoteAddress; @@ -255,7 +263,7 @@ public class OioDatagramChannel extends AbstractOioMessageChannel } else if (m instanceof ByteBuf) { data = (ByteBuf) m; } else { - BufUtil.release(buf.remove()); + ByteBufUtil.release(o); throw new ChannelException("unsupported message type: " + StringUtil.simpleClassName(o)); } @@ -272,8 +280,9 @@ public class OioDatagramChannel extends AbstractOioMessageChannel tmpPacket.setData(tmp); } socket.send(tmpPacket); + return 1; } finally { - BufUtil.release(o); + ByteBufUtil.release(o); } } diff --git a/transport/src/main/java/io/netty/channel/socket/oio/OioServerSocketChannel.java b/transport/src/main/java/io/netty/channel/socket/oio/OioServerSocketChannel.java index 6e40fb97d3..374181a03c 100755 --- a/transport/src/main/java/io/netty/channel/socket/oio/OioServerSocketChannel.java +++ b/transport/src/main/java/io/netty/channel/socket/oio/OioServerSocketChannel.java @@ -15,10 +15,10 @@ */ package io.netty.channel.socket.oio; -import io.netty.buffer.BufType; -import io.netty.buffer.MessageBuf; +import io.netty.buffer.ByteBufUtil; import io.netty.channel.ChannelException; import io.netty.channel.ChannelMetadata; +import io.netty.channel.MessageList; import io.netty.channel.oio.AbstractOioMessageChannel; import io.netty.channel.socket.ServerSocketChannel; import io.netty.util.internal.logging.InternalLogger; @@ -44,7 +44,7 @@ public class OioServerSocketChannel extends AbstractOioMessageChannel private static final InternalLogger logger = InternalLoggerFactory.getInstance(OioServerSocketChannel.class); - private static final ChannelMetadata METADATA = new ChannelMetadata(BufType.MESSAGE, false); + private static final ChannelMetadata METADATA = new ChannelMetadata(false); private static ServerSocket newServerSocket() { try { @@ -155,7 +155,7 @@ public class OioServerSocketChannel extends AbstractOioMessageChannel } @Override - protected int doReadMessages(MessageBuf buf) throws Exception { + protected int doReadMessages(MessageList buf) throws Exception { if (socket.isClosed()) { return -1; } @@ -183,6 +183,15 @@ public class OioServerSocketChannel extends AbstractOioMessageChannel return 0; } + @Override + protected int doWrite(MessageList msgs, int index) throws Exception { + int size = msgs.size(); + for (int i = index; i < size; i ++) { + ByteBufUtil.release(msgs.get(i)); + } + throw new UnsupportedOperationException(); + } + @Override protected void doConnect( SocketAddress remoteAddress, SocketAddress localAddress) throws Exception { @@ -198,9 +207,4 @@ public class OioServerSocketChannel extends AbstractOioMessageChannel protected void doDisconnect() throws Exception { throw new UnsupportedOperationException(); } - - @Override - protected void doWriteMessages(MessageBuf buf) throws Exception { - throw new UnsupportedOperationException(); - } } diff --git a/transport/src/main/java/io/netty/channel/socket/oio/OioServerSocketChannelConfig.java b/transport/src/main/java/io/netty/channel/socket/oio/OioServerSocketChannelConfig.java index 34ade6cb94..7595f63040 100644 --- a/transport/src/main/java/io/netty/channel/socket/oio/OioServerSocketChannelConfig.java +++ b/transport/src/main/java/io/netty/channel/socket/oio/OioServerSocketChannelConfig.java @@ -17,6 +17,7 @@ package io.netty.channel.socket.oio; import io.netty.buffer.ByteBufAllocator; import io.netty.channel.ChannelOption; +import io.netty.channel.RecvByteBufAllocator; import io.netty.channel.socket.ServerSocketChannelConfig; @@ -71,8 +72,8 @@ public interface OioServerSocketChannelConfig extends ServerSocketChannelConfig OioServerSocketChannelConfig setAllocator(ByteBufAllocator allocator); @Override - OioServerSocketChannelConfig setAutoRead(boolean autoRead); + OioServerSocketChannelConfig setRecvByteBufAllocator(RecvByteBufAllocator allocator); @Override - OioServerSocketChannelConfig setDefaultHandlerByteBufType(ChannelHandlerByteBufType type); + OioServerSocketChannelConfig setAutoRead(boolean autoRead); } diff --git a/transport/src/main/java/io/netty/channel/socket/oio/OioSocketChannelConfig.java b/transport/src/main/java/io/netty/channel/socket/oio/OioSocketChannelConfig.java index d18db6a109..ac1a481552 100644 --- a/transport/src/main/java/io/netty/channel/socket/oio/OioSocketChannelConfig.java +++ b/transport/src/main/java/io/netty/channel/socket/oio/OioSocketChannelConfig.java @@ -18,6 +18,7 @@ package io.netty.channel.socket.oio; import io.netty.buffer.ByteBufAllocator; import io.netty.channel.ChannelConfig; import io.netty.channel.ChannelOption; +import io.netty.channel.RecvByteBufAllocator; import io.netty.channel.socket.SocketChannelConfig; /** @@ -86,8 +87,8 @@ public interface OioSocketChannelConfig extends SocketChannelConfig { OioSocketChannelConfig setAllocator(ByteBufAllocator allocator); @Override - OioSocketChannelConfig setAutoRead(boolean autoRead); + OioSocketChannelConfig setRecvByteBufAllocator(RecvByteBufAllocator allocator); @Override - OioSocketChannelConfig setDefaultHandlerByteBufType(ChannelHandlerByteBufType type); + OioSocketChannelConfig setAutoRead(boolean autoRead); } diff --git a/transport/src/test/java/io/netty/bootstrap/BootstrapTest.java b/transport/src/test/java/io/netty/bootstrap/BootstrapTest.java index ad630b5d37..e99b4fdc54 100644 --- a/transport/src/test/java/io/netty/bootstrap/BootstrapTest.java +++ b/transport/src/test/java/io/netty/bootstrap/BootstrapTest.java @@ -17,9 +17,8 @@ package io.netty.bootstrap; import io.netty.channel.ChannelHandler.Sharable; -import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.ChannelInboundMessageHandler; -import io.netty.channel.ChannelInboundMessageHandlerAdapter; +import io.netty.channel.ChannelInboundHandler; +import io.netty.channel.ChannelInboundHandlerAdapter; import io.netty.channel.EventLoopGroup; import io.netty.channel.local.LocalAddress; import io.netty.channel.local.LocalChannel; @@ -38,7 +37,7 @@ public class BootstrapTest { EventLoopGroup groupB = new LocalEventLoopGroup(1); try { - ChannelInboundMessageHandler dummyHandler = new DummyHandler(); + ChannelInboundHandler dummyHandler = new DummyHandler(); final Bootstrap bootstrapA = new Bootstrap(); bootstrapA.group(groupA); @@ -84,7 +83,7 @@ public class BootstrapTest { EventLoopGroup groupB = new LocalEventLoopGroup(1); try { - ChannelInboundMessageHandler dummyHandler = new DummyHandler(); + ChannelInboundHandler dummyHandler = new DummyHandler(); final Bootstrap bootstrapA = new Bootstrap(); bootstrapA.group(groupA); @@ -125,10 +124,5 @@ public class BootstrapTest { } @Sharable - private static final class DummyHandler extends ChannelInboundMessageHandlerAdapter { - @Override - public void messageReceived(ChannelHandlerContext ctx, Object msg) throws Exception { - // NOOP - } - } + private static final class DummyHandler extends ChannelInboundHandlerAdapter { } } diff --git a/transport/src/test/java/io/netty/channel/AbstractEventLoopTest.java b/transport/src/test/java/io/netty/channel/AbstractEventLoopTest.java index d318b9d689..d9c3f45c83 100644 --- a/transport/src/test/java/io/netty/channel/AbstractEventLoopTest.java +++ b/transport/src/test/java/io/netty/channel/AbstractEventLoopTest.java @@ -39,7 +39,6 @@ public abstract class AbstractEventLoopTest { ServerBootstrap bootstrap = new ServerBootstrap(); ChannelFuture future = bootstrap.channel(newChannel()).group(group) .childHandler(new ChannelInitializer() { - @Override public void initChannel(SocketChannel ch) throws Exception { } @@ -61,27 +60,11 @@ public abstract class AbstractEventLoopTest { assertSame(executor, future.channel().pipeline().context(TestChannelHandler2.class).executor()); } - private static final class TestChannelHandler extends ChannelDuplexHandler { - @Override - public void flush(ChannelHandlerContext ctx, ChannelPromise promise) throws Exception { - ctx.flush(promise); - } - - @Override - public void inboundBufferUpdated(ChannelHandlerContext ctx) throws Exception { - ctx.fireInboundBufferUpdated(); - } - } + private static final class TestChannelHandler extends ChannelDuplexHandler { } private static final class TestChannelHandler2 extends ChannelDuplexHandler { @Override - public void flush(ChannelHandlerContext ctx, ChannelPromise promise) throws Exception { - ctx.flush(promise); - } - - @Override - public void inboundBufferUpdated(ChannelHandlerContext ctx) throws Exception { - } + public void messageReceived(ChannelHandlerContext ctx, MessageList msgs) throws Exception { } } protected abstract EventLoopGroup newEventLoopGroup(); diff --git a/transport/src/test/java/io/netty/channel/DefaultChannelPipelineTest.java b/transport/src/test/java/io/netty/channel/DefaultChannelPipelineTest.java index 805bdc25c0..00c85a86e0 100644 --- a/transport/src/test/java/io/netty/channel/DefaultChannelPipelineTest.java +++ b/transport/src/test/java/io/netty/channel/DefaultChannelPipelineTest.java @@ -18,10 +18,7 @@ package io.netty.channel; import io.netty.bootstrap.Bootstrap; import io.netty.bootstrap.ServerBootstrap; -import io.netty.buffer.ByteBuf; -import io.netty.buffer.MessageBuf; import io.netty.buffer.ReferenceCounted; -import io.netty.buffer.Unpooled; import io.netty.channel.ChannelHandler.Sharable; import io.netty.channel.local.LocalAddress; import io.netty.channel.local.LocalChannel; @@ -36,7 +33,6 @@ import java.util.Collections; import java.util.List; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicReference; import static org.junit.Assert.*; @@ -57,14 +53,14 @@ public class DefaultChannelPipelineTest { final AtomicReference peerRef = new AtomicReference(); ServerBootstrap sb = new ServerBootstrap(); sb.group(group).channel(LocalServerChannel.class); - sb.childHandler(new ChannelInboundMessageHandlerAdapter() { + sb.childHandler(new ChannelInboundHandlerAdapter() { @Override public void channelRegistered(ChannelHandlerContext ctx) throws Exception { peerRef.set(ctx.channel()); } @Override - public void messageReceived(ChannelHandlerContext ctx, Object msg) throws Exception { + public void messageReceived(ChannelHandlerContext ctx, MessageList msgs) throws Exception { // Swallow. } }); @@ -97,76 +93,6 @@ public class DefaultChannelPipelineTest { } } - @Test - public void testMessageCatchAllInboundSink() throws Exception { - final AtomicBoolean forwarded = new AtomicBoolean(); - - setUp(new ChannelInboundMessageHandlerAdapter() { - @Override - public void messageReceived(ChannelHandlerContext ctx, Object msg) throws Exception { - forwarded.set(ctx.nextInboundMessageBuffer().add(msg)); - } - - @Override - public void endMessageReceived(ChannelHandlerContext ctx) throws Exception { - ctx.fireInboundBufferUpdated(); - } - }); - - peer.write(new Object()).sync(); - - assertTrue(forwarded.get()); - } - - @Test - public void testByteCatchAllInboundSink() throws Exception { - final AtomicBoolean forwarded = new AtomicBoolean(); - setUp(new ChannelInboundByteHandlerAdapter() { - @Override - protected void inboundBufferUpdated(ChannelHandlerContext ctx, ByteBuf in) throws Exception { - ByteBuf out = ctx.nextInboundByteBuffer(); - out.writeBytes(in); - forwarded.set(true); - ctx.fireInboundBufferUpdated(); - } - }); - - // Not using peer.write() because the pipeline will convert the bytes into a message automatically. - self.eventLoop().submit(new Runnable() { - @Override - public void run() { - self.pipeline().inboundByteBuffer().writeByte(0); - self.pipeline().fireInboundBufferUpdated(); - } - }).sync(); - - assertTrue(forwarded.get()); - } - - @Test - public void testByteCatchAllOutboundSink() throws Exception { - final AtomicBoolean forwarded = new AtomicBoolean(); - setUp(new ChannelOutboundByteHandlerAdapter() { - @Override - protected void flush(ChannelHandlerContext ctx, ByteBuf in, ChannelPromise promise) throws Exception { - ByteBuf out = ctx.nextOutboundByteBuffer(); - out.writeBytes(in); - forwarded.set(true); - ctx.flush(promise); - } - }); - - self.eventLoop().submit(new Runnable() { - @Override - public void run() { - self.pipeline().outboundByteBuffer().writeByte(0); - self.pipeline().flush(); - } - }).sync(); - - assertTrue(forwarded.get()); - } - @Test public void testFreeCalled() throws Exception { final CountDownLatch free = new CountDownLatch(1); @@ -214,18 +140,22 @@ public class DefaultChannelPipelineTest { assertTrue(handler.called); } - private static final class StringInboundHandler extends ChannelInboundMessageHandlerAdapter { + private static final class StringInboundHandler extends ChannelInboundHandlerAdapter { boolean called; @Override - public boolean acceptInboundMessage(Object msg) throws Exception { + public void messageReceived(ChannelHandlerContext ctx, MessageList msgs) throws Exception { called = true; - return super.acceptInboundMessage(msg); - } + MessageList out = MessageList.newInstance(); + for (int i = 0; i < msgs.size(); i ++) { + Object m = msgs.get(i); + if (!(m instanceof String)) { + out.add(m); + } + } - @Override - public void messageReceived(ChannelHandlerContext ctx, String msg) throws Exception { - fail(); + msgs.recycle(); + ctx.fireMessageReceived(out); } } @@ -347,294 +277,6 @@ public class DefaultChannelPipelineTest { verifyContextNumber(pipeline, 8); } - @Test(timeout = 100000) - public void testRemoveAndForwardInboundByte() throws Exception { - final ChannelInboundByteHandlerImpl handler1 = new ChannelInboundByteHandlerImpl(); - final ChannelInboundByteHandlerImpl handler2 = new ChannelInboundByteHandlerImpl(); - - setUp(handler1, handler2); - - self.eventLoop().submit(new Runnable() { - @Override - public void run() { - ChannelPipeline p = self.pipeline(); - p.context(handler1).inboundByteBuffer().writeLong(8); - assertEquals(8, p.context(handler1).inboundByteBuffer().readableBytes()); - assertEquals(0, p.context(handler2).inboundByteBuffer().readableBytes()); - p.remove(handler1); - assertEquals(8, p.context(handler2).inboundByteBuffer().readableBytes()); - } - }).sync(); - - assertTrue(handler2.updated); - } - - @Test(timeout = 100000) - public void testReplaceAndForwardInboundByte() throws Exception { - final ChannelInboundByteHandlerImpl handler1 = new ChannelInboundByteHandlerImpl(); - final ChannelInboundByteHandlerImpl handler2 = new ChannelInboundByteHandlerImpl(); - - setUp(handler1); - - self.eventLoop().submit(new Runnable() { - @Override - public void run() { - ChannelPipeline p = self.pipeline(); - p.context(handler1).inboundByteBuffer().writeLong(8); - assertEquals(8, p.context(handler1).inboundByteBuffer().readableBytes()); - p.replace(handler1, "handler2", handler2); - assertEquals(8, p.context(handler2).inboundByteBuffer().readableBytes()); - } - }).sync(); - - assertTrue(handler2.updated); - } - - @Test(timeout = 10000) - public void testRemoveAndForwardOutboundByte() throws Exception { - final ChannelOutboundByteHandlerImpl handler1 = new ChannelOutboundByteHandlerImpl(); - final ChannelOutboundByteHandlerImpl handler2 = new ChannelOutboundByteHandlerImpl(); - - setUp(handler1, handler2); - - self.eventLoop().submit(new Runnable() { - @Override - public void run() { - ChannelPipeline p = self.pipeline(); - p.context(handler2).outboundByteBuffer().writeLong(8); - assertEquals(8, p.context(handler2).outboundByteBuffer().readableBytes()); - assertEquals(0, p.context(handler1).outboundByteBuffer().readableBytes()); - self.pipeline().remove(handler2); - assertEquals(8, p.context(handler1).outboundByteBuffer().readableBytes()); - } - }).sync(); - - assertTrue(handler1.flushed); - } - - @Test(timeout = 10000) - public void testReplaceAndForwardOutboundByte() throws Exception { - final ChannelOutboundByteHandlerImpl handler1 = new ChannelOutboundByteHandlerImpl(); - final ChannelOutboundByteHandlerImpl handler2 = new ChannelOutboundByteHandlerImpl(); - - setUp(handler1); - - self.eventLoop().submit(new Runnable() { - @Override - public void run() { - ChannelPipeline p = self.pipeline(); - p.context(handler1).outboundByteBuffer().writeLong(8); - assertEquals(8, p.context(handler1).outboundByteBuffer().readableBytes()); - p.replace(handler1, "handler2", handler2); - assertEquals(8, p.context(handler2).outboundByteBuffer().readableBytes()); - } - }).sync(); - - assertTrue(handler2.flushed); - } - - @Test(timeout = 10000) - public void testReplaceAndForwardDuplexByte() throws Exception { - final ByteHandlerImpl handler1 = new ByteHandlerImpl(); - final ByteHandlerImpl handler2 = new ByteHandlerImpl(); - - setUp(handler1); - - self.eventLoop().submit(new Runnable() { - @Override - public void run() { - ChannelPipeline p = self.pipeline(); - p.context(handler1).outboundByteBuffer().writeLong(8); - p.context(handler1).inboundByteBuffer().writeLong(8); - - assertEquals(8, p.context(handler1).outboundByteBuffer().readableBytes()); - assertEquals(8, p.context(handler1).inboundByteBuffer().readableBytes()); - - p.replace(handler1, "handler2", handler2); - assertEquals(8, p.context(handler2).outboundByteBuffer().readableBytes()); - assertEquals(8, p.context(handler2).inboundByteBuffer().readableBytes()); - } - }).sync(); - - assertTrue(((ChannelInboundByteHandlerImpl) handler2.stateHandler()).updated); - assertTrue(((ChannelOutboundByteHandlerImpl) handler2.operationHandler()).flushed); - } - - @Test(timeout = 10000) - public void testRemoveAndForwardDuplexByte() throws Exception { - final ChannelOutboundByteHandlerImpl handler1 = new ChannelOutboundByteHandlerImpl(); - final ByteHandlerImpl handler2 = new ByteHandlerImpl(); - final ChannelInboundByteHandlerImpl handler3 = new ChannelInboundByteHandlerImpl(); - - setUp(handler1, handler2, handler3); - - self.eventLoop().submit(new Runnable() { - @Override - public void run() { - ChannelPipeline p = self.pipeline(); - p.context(handler2).outboundByteBuffer().writeLong(8); - p.context(handler2).inboundByteBuffer().writeLong(8); - - assertEquals(8, p.context(handler2).outboundByteBuffer().readableBytes()); - assertEquals(8, p.context(handler2).inboundByteBuffer().readableBytes()); - - assertEquals(0, p.context(handler1).outboundByteBuffer().readableBytes()); - assertEquals(0, p.context(handler3).inboundByteBuffer().readableBytes()); - - p.remove(handler2); - assertEquals(8, p.context(handler1).outboundByteBuffer().readableBytes()); - assertEquals(8, p.context(handler3).inboundByteBuffer().readableBytes()); - } - }).sync(); - - assertTrue(handler1.flushed); - assertTrue(handler3.updated); - } - - @Test(timeout = 10000) - public void testRemoveAndForwardInboundMessage() throws Exception { - final ChannelInboundMessageHandlerImpl handler1 = new ChannelInboundMessageHandlerImpl(); - final ChannelInboundMessageHandlerImpl handler2 = new ChannelInboundMessageHandlerImpl(); - - setUp(handler1, handler2); - - self.eventLoop().submit(new Runnable() { - @Override - public void run() { - ChannelPipeline p = self.pipeline(); - p.context(handler1).inboundMessageBuffer().add(new Object()); - assertEquals(1, p.context(handler1).inboundMessageBuffer().size()); - assertEquals(0, p.context(handler2).inboundMessageBuffer().size()); - p.remove(handler1); - assertEquals(1, p.context(handler2).inboundMessageBuffer().size()); - } - }).sync(); - - assertTrue(handler2.updated); - } - - @Test(timeout = 10000) - public void testReplaceAndForwardInboundMessage() throws Exception { - final ChannelInboundMessageHandlerImpl handler1 = new ChannelInboundMessageHandlerImpl(); - final ChannelInboundMessageHandlerImpl handler2 = new ChannelInboundMessageHandlerImpl(); - - setUp(handler1); - - self.eventLoop().submit(new Runnable() { - @Override - public void run() { - ChannelPipeline p = self.pipeline(); - p.context(handler1).inboundMessageBuffer().add(new Object()); - assertEquals(1, p.context(handler1).inboundMessageBuffer().size()); - p.replace(handler1, "handler2", handler2); - assertEquals(1, p.context(handler2).inboundMessageBuffer().size()); - } - }).sync(); - - assertTrue(handler2.updated); - } - - @Test(timeout = 10000) - public void testRemoveAndForwardOutboundMessage() throws Exception { - final ChannelOutboundMessageHandlerImpl handler1 = new ChannelOutboundMessageHandlerImpl(); - final ChannelOutboundMessageHandlerImpl handler2 = new ChannelOutboundMessageHandlerImpl(); - - setUp(handler1, handler2); - - self.eventLoop().submit(new Runnable() { - @Override - public void run() { - ChannelPipeline p = self.pipeline(); - p.context(handler2).outboundMessageBuffer().add(new Object()); - assertEquals(1, p.context(handler2).outboundMessageBuffer().size()); - assertEquals(0, p.context(handler1).outboundMessageBuffer().size()); - p.remove(handler2); - assertEquals(1, p.context(handler1).outboundMessageBuffer().size()); - } - }).sync(); - - assertTrue(handler1.flushed); - } - - @Test(timeout = 10000) - public void testReplaceAndForwardOutboundMessage() throws Exception { - final ChannelOutboundMessageHandlerImpl handler1 = new ChannelOutboundMessageHandlerImpl(); - final ChannelOutboundMessageHandlerImpl handler2 = new ChannelOutboundMessageHandlerImpl(); - - setUp(handler1); - - self.eventLoop().submit(new Runnable() { - @Override - public void run() { - ChannelPipeline p = self.pipeline(); - p.context(handler1).outboundMessageBuffer().add(new Object()); - assertEquals(1, p.context(handler1).outboundMessageBuffer().size()); - p.replace(handler1, "handler2", handler2); - assertEquals(1, p.context(handler2).outboundMessageBuffer().size()); - } - }).sync(); - - assertTrue(handler2.flushed); - } - - @Test(timeout = 10000) - public void testReplaceAndForwardDuplexMessage() throws Exception { - final MessageHandlerImpl handler1 = new MessageHandlerImpl(); - final MessageHandlerImpl handler2 = new MessageHandlerImpl(); - - setUp(handler1); - - self.eventLoop().submit(new Runnable() { - @Override - public void run() { - ChannelPipeline p = self.pipeline(); - p.context(handler1).outboundMessageBuffer().add(new Object()); - p.context(handler1).inboundMessageBuffer().add(new Object()); - - assertEquals(1, p.context(handler1).outboundMessageBuffer().size()); - assertEquals(1, p.context(handler1).inboundMessageBuffer().size()); - - p.replace(handler1, "handler2", handler2); - assertEquals(1, p.context(handler2).outboundMessageBuffer().size()); - assertEquals(1, p.context(handler2).inboundMessageBuffer().size()); - } - }).sync(); - - assertTrue(((ChannelInboundMessageHandlerImpl) handler2.stateHandler()).updated); - assertTrue(((ChannelOutboundMessageHandlerImpl) handler2.operationHandler()).flushed); - } - - @Test(timeout = 10000) - public void testRemoveAndForwardDuplexMessage() throws Exception { - final ChannelOutboundMessageHandlerImpl handler1 = new ChannelOutboundMessageHandlerImpl(); - final MessageHandlerImpl handler2 = new MessageHandlerImpl(); - final ChannelInboundMessageHandlerImpl handler3 = new ChannelInboundMessageHandlerImpl(); - - setUp(handler1, handler2, handler3); - - self.eventLoop().submit(new Runnable() { - @Override - public void run() { - ChannelPipeline p = self.pipeline(); - p.context(handler2).outboundMessageBuffer().add(new Object()); - p.context(handler2).inboundMessageBuffer().add(new Object()); - - assertEquals(1, p.context(handler2).outboundMessageBuffer().size()); - assertEquals(1, p.context(handler2).inboundMessageBuffer().size()); - - assertEquals(0, p.context(handler1).outboundMessageBuffer().size()); - assertEquals(0, p.context(handler3).inboundMessageBuffer().size()); - - p.remove(handler2); - assertEquals(1, p.context(handler1).outboundMessageBuffer().size()); - assertEquals(1, p.context(handler3).inboundMessageBuffer().size()); - } - }).sync(); - - assertTrue(handler1.flushed); - assertTrue(handler3.updated); - } - @Test(timeout = 10000) public void testLifeCycleAwareness() throws Exception { setUp(); @@ -684,6 +326,122 @@ public class DefaultChannelPipelineTest { removeLatch.await(); } + @Test(timeout = 100000) + public void testRemoveAndForwardInbound() throws Exception { + final BufferedTestHandler handler1 = new BufferedTestHandler(); + final BufferedTestHandler handler2 = new BufferedTestHandler(); + + setUp(handler1, handler2); + + self.eventLoop().submit(new Runnable() { + @Override + public void run() { + ChannelPipeline p = self.pipeline(); + handler1.inboundBuffer.add(8); + assertEquals(8, handler1.inboundBuffer.get(0)); + assertTrue(handler2.inboundBuffer.isEmpty()); + p.remove(handler1); + assertEquals(1, handler2.inboundBuffer.size()); + assertEquals(8, handler2.inboundBuffer.get(0)); + } + }).sync(); + } + + @Test(timeout = 10000) + public void testRemoveAndForwardOutbound() throws Exception { + final BufferedTestHandler handler1 = new BufferedTestHandler(); + final BufferedTestHandler handler2 = new BufferedTestHandler(); + + setUp(handler1, handler2); + + self.eventLoop().submit(new Runnable() { + @Override + public void run() { + ChannelPipeline p = self.pipeline(); + handler2.outboundBuffer.add(8); + assertEquals(8, handler2.outboundBuffer.get(0)); + assertTrue(handler1.outboundBuffer.isEmpty()); + p.remove(handler2); + assertEquals(1, handler1.outboundBuffer.size()); + assertEquals(8, handler1.outboundBuffer.get(0)); + } + }).sync(); + } + + @Test(timeout = 10000) + public void testReplaceAndForwardOutbound() throws Exception { + final BufferedTestHandler handler1 = new BufferedTestHandler(); + final BufferedTestHandler handler2 = new BufferedTestHandler(); + + setUp(handler1); + + self.eventLoop().submit(new Runnable() { + @Override + public void run() { + ChannelPipeline p = self.pipeline(); + handler1.outboundBuffer.add(8); + assertEquals(8, handler1.outboundBuffer.get(0)); + assertTrue(handler2.outboundBuffer.isEmpty()); + p.replace(handler1, "handler2", handler2); + assertEquals(8, handler2.outboundBuffer.get(0)); + } + }).sync(); + } + + @Test(timeout = 10000) + public void testReplaceAndForwardInboundAndOutbound() throws Exception { + final BufferedTestHandler handler1 = new BufferedTestHandler(); + final BufferedTestHandler handler2 = new BufferedTestHandler(); + + setUp(handler1); + + self.eventLoop().submit(new Runnable() { + @Override + public void run() { + ChannelPipeline p = self.pipeline(); + handler1.inboundBuffer.add(8); + handler1.outboundBuffer.add(8); + + assertEquals(8, handler1.inboundBuffer.get(0)); + assertEquals(8, handler1.outboundBuffer.get(0)); + assertTrue(handler2.inboundBuffer.isEmpty()); + assertTrue(handler2.outboundBuffer.isEmpty()); + + p.replace(handler1, "handler2", handler2); + assertEquals(8, handler2.outboundBuffer.get(0)); + assertEquals(8, handler2.inboundBuffer.get(0)); + } + }).sync(); + } + + @Test(timeout = 10000) + public void testRemoveAndForwardInboundOutbound() throws Exception { + final BufferedTestHandler handler1 = new BufferedTestHandler(); + final BufferedTestHandler handler2 = new BufferedTestHandler(); + final BufferedTestHandler handler3 = new BufferedTestHandler(); + + setUp(handler1, handler2, handler3); + + self.eventLoop().submit(new Runnable() { + @Override + public void run() { + ChannelPipeline p = self.pipeline(); + handler2.inboundBuffer.add(8); + handler2.outboundBuffer.add(8); + + assertEquals(8, handler2.inboundBuffer.get(0)); + assertEquals(8, handler2.outboundBuffer.get(0)); + + assertEquals(0, handler1.outboundBuffer.size()); + assertEquals(0, handler3.inboundBuffer.size()); + + p.remove(handler2); + assertEquals(8, handler3.inboundBuffer.get(0)); + assertEquals(8, handler1.outboundBuffer.get(0)); + } + }).sync(); + } + private static int next(DefaultChannelHandlerContext ctx) { DefaultChannelHandlerContext next = ctx.next; if (next == null) { @@ -727,109 +485,37 @@ public class DefaultChannelPipelineTest { } @Sharable - private static class TestHandler extends ChannelDuplexHandler { + private static class TestHandler extends ChannelDuplexHandler { } + + private static class BufferedTestHandler extends ChannelDuplexHandler { + final MessageList inboundBuffer = MessageList.newInstance(); + final MessageList outboundBuffer = MessageList.newInstance(); + @Override - public void flush(ChannelHandlerContext ctx, ChannelPromise promise) throws Exception { - ctx.flush(promise); + public void write(ChannelHandlerContext ctx, MessageList msgs, ChannelPromise promise) + throws Exception { + for (int i = 0; i < msgs.size(); i++) { + outboundBuffer.add(msgs.get(i)); + } + msgs.recycle(); } @Override - public void inboundBufferUpdated(ChannelHandlerContext ctx) throws Exception { - ctx.fireInboundBufferUpdated(); - } - } - - private static final class ChannelInboundByteHandlerImpl extends ChannelInboundByteHandlerAdapter { - boolean updated; - - @Override - protected void inboundBufferUpdated(ChannelHandlerContext ctx, ByteBuf in) throws Exception { - updated = true; - } - } - - private static final class ChannelOutboundByteHandlerImpl extends ChannelOutboundByteHandlerAdapter { - boolean flushed; - - @Override - protected void flush(ChannelHandlerContext ctx, ByteBuf in, ChannelPromise promise) throws Exception { - promise.setSuccess(); - flushed = true; - } - } - - private static final class ChannelInboundMessageHandlerImpl extends ChannelStateHandlerAdapter - implements ChannelInboundMessageHandler { - boolean updated; - @Override - public MessageBuf newInboundBuffer(ChannelHandlerContext ctx) throws Exception { - return Unpooled.messageBuffer(); + public void messageReceived(ChannelHandlerContext ctx, MessageList msgs) throws Exception { + for (int i = 0; i < msgs.size(); i++) { + inboundBuffer.add(msgs.get(i)); + } + msgs.recycle(); } @Override - public void inboundBufferUpdated(ChannelHandlerContext ctx) throws Exception { - updated = true; - } - } - - private static final class ChannelOutboundMessageHandlerImpl extends ChannelOperationHandlerAdapter - implements ChannelOutboundMessageHandler { - boolean flushed; - @Override - public MessageBuf newOutboundBuffer(ChannelHandlerContext ctx) throws Exception { - return Unpooled.messageBuffer(); - } - - @Override - public void flush(ChannelHandlerContext ctx, ChannelPromise promise) throws Exception { - promise.setSuccess(); - flushed = true; - } - } - - private static final class ByteHandlerImpl extends CombinedChannelDuplexHandler - implements ChannelInboundByteHandler, ChannelOutboundByteHandler { - ByteHandlerImpl() { - super(new ChannelInboundByteHandlerImpl(), new ChannelOutboundByteHandlerImpl()); - } - - @Override - public ByteBuf newInboundBuffer(ChannelHandlerContext ctx) throws Exception { - return ((ChannelInboundByteHandler) stateHandler()).newInboundBuffer(ctx); - } - - @Override - public void discardInboundReadBytes(ChannelHandlerContext ctx) throws Exception { - ((ChannelInboundByteHandler) stateHandler()).discardInboundReadBytes(ctx); - } - - @Override - public ByteBuf newOutboundBuffer(ChannelHandlerContext ctx) throws Exception { - return ((ChannelOutboundByteHandler) operationHandler()).newOutboundBuffer(ctx); - } - - @Override - public void discardOutboundReadBytes(ChannelHandlerContext ctx) throws Exception { - ((ChannelOutboundByteHandler) operationHandler()).discardOutboundReadBytes(ctx); - } - } - - private static final class MessageHandlerImpl extends CombinedChannelDuplexHandler - implements ChannelInboundMessageHandler, ChannelOutboundMessageHandler { - MessageHandlerImpl() { - super(new ChannelInboundMessageHandlerImpl(), new ChannelOutboundMessageHandlerImpl()); - } - - @SuppressWarnings("unchecked") - @Override - public MessageBuf newInboundBuffer(ChannelHandlerContext ctx) throws Exception { - return ((ChannelInboundMessageHandler) stateHandler()).newInboundBuffer(ctx); - } - - @SuppressWarnings("unchecked") - @Override - public MessageBuf newOutboundBuffer(ChannelHandlerContext ctx) throws Exception { - return ((ChannelOutboundMessageHandler) operationHandler()).newOutboundBuffer(ctx); + public void handlerRemoved(ChannelHandlerContext ctx) throws Exception { + if (!inboundBuffer.isEmpty()) { + ctx.fireMessageReceived(inboundBuffer); + } + if (!outboundBuffer.isEmpty()) { + ctx.write(outboundBuffer); + } } } diff --git a/transport/src/test/java/io/netty/channel/group/DefaultChannnelGroupTest.java b/transport/src/test/java/io/netty/channel/group/DefaultChannnelGroupTest.java index 99876ae266..43af68aa77 100644 --- a/transport/src/test/java/io/netty/channel/group/DefaultChannnelGroupTest.java +++ b/transport/src/test/java/io/netty/channel/group/DefaultChannnelGroupTest.java @@ -18,7 +18,7 @@ package io.netty.channel.group; import io.netty.bootstrap.ServerBootstrap; import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.ChannelStateHandlerAdapter; +import io.netty.channel.ChannelInboundHandlerAdapter; import io.netty.channel.EventLoopGroup; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.nio.NioServerSocketChannel; @@ -36,15 +36,11 @@ public class DefaultChannnelGroupTest { ServerBootstrap b = new ServerBootstrap(); b.group(bossGroup, workerGroup); - b.childHandler(new ChannelStateHandlerAdapter() { + b.childHandler(new ChannelInboundHandlerAdapter() { @Override public void channelActive(ChannelHandlerContext ctx) { allChannels.add(ctx.channel()); } - - @Override - public void inboundBufferUpdated(ChannelHandlerContext ctx) { - } }); b.channel(NioServerSocketChannel.class); diff --git a/transport/src/test/java/io/netty/channel/local/LocalChannelRegistryTest.java b/transport/src/test/java/io/netty/channel/local/LocalChannelRegistryTest.java index 17a1bc9393..830c77be58 100644 --- a/transport/src/test/java/io/netty/channel/local/LocalChannelRegistryTest.java +++ b/transport/src/test/java/io/netty/channel/local/LocalChannelRegistryTest.java @@ -19,9 +19,10 @@ import io.netty.bootstrap.Bootstrap; import io.netty.bootstrap.ServerBootstrap; import io.netty.channel.Channel; import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.ChannelInboundMessageHandlerAdapter; +import io.netty.channel.ChannelInboundHandlerAdapter; import io.netty.channel.ChannelInitializer; import io.netty.channel.EventLoopGroup; +import io.netty.channel.MessageList; import io.netty.util.internal.logging.InternalLogger; import io.netty.util.internal.logging.InternalLoggerFactory; import org.junit.Test; @@ -70,8 +71,7 @@ public class LocalChannelRegistryTest { @Override public void run() { // Send a message event up the pipeline. - cc.pipeline().inboundMessageBuffer().add("Hello, World"); - cc.pipeline().fireInboundBufferUpdated(); + cc.pipeline().fireMessageReceived("Hello, World"); latch.countDown(); } }); @@ -91,10 +91,12 @@ public class LocalChannelRegistryTest { } } - static class TestHandler extends ChannelInboundMessageHandlerAdapter { + static class TestHandler extends ChannelInboundHandlerAdapter { @Override - public void messageReceived(ChannelHandlerContext ctx, String msg) throws Exception { - logger.info(String.format("Received mesage: %s", msg)); + public void messageReceived(ChannelHandlerContext ctx, MessageList msgs) throws Exception { + for (int i = 0; i < msgs.size(); i ++) { + logger.info(String.format("Received mesage: %s", msgs.get(i))); + } } } } diff --git a/transport/src/test/java/io/netty/channel/local/LocalTransportThreadModelTest.java b/transport/src/test/java/io/netty/channel/local/LocalTransportThreadModelTest.java index 01c741d756..59bca7c134 100644 --- a/transport/src/test/java/io/netty/channel/local/LocalTransportThreadModelTest.java +++ b/transport/src/test/java/io/netty/channel/local/LocalTransportThreadModelTest.java @@ -17,20 +17,14 @@ package io.netty.channel.local; import io.netty.bootstrap.ServerBootstrap; import io.netty.buffer.ByteBuf; -import io.netty.buffer.MessageBuf; -import io.netty.buffer.Unpooled; import io.netty.channel.Channel; import io.netty.channel.ChannelDuplexHandler; import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.ChannelHandlerUtil; -import io.netty.channel.ChannelInboundByteHandler; -import io.netty.channel.ChannelInboundMessageHandler; -import io.netty.channel.ChannelInboundMessageHandlerAdapter; +import io.netty.channel.ChannelInboundHandlerAdapter; import io.netty.channel.ChannelInitializer; -import io.netty.channel.ChannelOutboundByteHandler; -import io.netty.channel.ChannelOutboundMessageHandler; import io.netty.channel.ChannelPromise; import io.netty.channel.EventLoopGroup; +import io.netty.channel.MessageList; import io.netty.util.concurrent.DefaultEventExecutorGroup; import io.netty.util.concurrent.DefaultThreadFactory; import io.netty.util.concurrent.EventExecutorGroup; @@ -62,9 +56,9 @@ public class LocalTransportThreadModelTest { .childHandler(new ChannelInitializer() { @Override public void initChannel(LocalChannel ch) throws Exception { - ch.pipeline().addLast(new ChannelInboundMessageHandlerAdapter() { + ch.pipeline().addLast(new ChannelInboundHandlerAdapter() { @Override - public void messageReceived(ChannelHandlerContext ctx, Object msg) { + public void messageReceived(ChannelHandlerContext ctx, MessageList msgs) { // Discard } }); @@ -107,15 +101,15 @@ public class LocalTransportThreadModelTest { l.register(ch).sync().channel().connect(localAddr).sync(); // Fire inbound events from all possible starting points. - ch.pipeline().fireInboundBufferUpdated(); - ch.pipeline().context(h1).fireInboundBufferUpdated(); - ch.pipeline().context(h2).fireInboundBufferUpdated(); - ch.pipeline().context(h3).fireInboundBufferUpdated(); + ch.pipeline().fireMessageReceived("1"); + ch.pipeline().context(h1).fireMessageReceived("2"); + ch.pipeline().context(h2).fireMessageReceived("3"); + ch.pipeline().context(h3).fireMessageReceived("4"); // Fire outbound events from all possible starting points. - ch.pipeline().flush(); - ch.pipeline().context(h3).flush(); - ch.pipeline().context(h2).flush(); - ch.pipeline().context(h1).flush().sync(); + ch.pipeline().write("5"); + ch.pipeline().context(h3).write("6"); + ch.pipeline().context(h2).write("7"); + ch.pipeline().context(h1).write("8").sync(); ch.close().sync(); @@ -229,7 +223,6 @@ public class LocalTransportThreadModelTest { } @Test(timeout = 30000) - @Ignore("regression test") public void testConcurrentMessageBufferAccess() throws Throwable { EventLoopGroup l = new LocalEventLoopGroup(4, new DefaultThreadFactory("l")); EventExecutorGroup e1 = new DefaultEventExecutorGroup(4, new DefaultThreadFactory("e1")); @@ -270,11 +263,11 @@ public class LocalTransportThreadModelTest { ch.eventLoop().execute(new Runnable() { @Override public void run() { - MessageBuf buf = ch.pipeline().inboundMessageBuffer(); + MessageList msgs = MessageList.newInstance(end - start); for (int j = start; j < end; j ++) { - buf.add(Integer.valueOf(j)); + msgs.add(Integer.valueOf(j)); } - ch.pipeline().fireInboundBufferUpdated(); + ch.pipeline().fireMessageReceived(msgs); } }); } @@ -310,11 +303,12 @@ public class LocalTransportThreadModelTest { ch.pipeline().context(h6).executor().execute(new Runnable() { @Override public void run() { - MessageBuf buf = ch.pipeline().outboundMessageBuffer(); + MessageList msgs = MessageList.newInstance(end - start); for (int j = start; j < end; j ++) { - buf.add(Integer.valueOf(j)); + msgs.add(Integer.valueOf(j)); } - ch.pipeline().flush(); + + ch.pipeline().write(msgs); } }); } @@ -353,10 +347,7 @@ public class LocalTransportThreadModelTest { } } - private static class ThreadNameAuditor - extends ChannelDuplexHandler - implements ChannelInboundMessageHandler, - ChannelOutboundMessageHandler { + private static class ThreadNameAuditor extends ChannelDuplexHandler { private final AtomicReference exception = new AtomicReference(); @@ -364,40 +355,21 @@ public class LocalTransportThreadModelTest { private final Queue outboundThreadNames = new ConcurrentLinkedQueue(); private final Queue removalThreadNames = new ConcurrentLinkedQueue(); - @Override - public MessageBuf newInboundBuffer(ChannelHandlerContext ctx) throws Exception { - return Unpooled.messageBuffer(); - } - - @Override - public MessageBuf newOutboundBuffer(ChannelHandlerContext ctx) throws Exception { - return Unpooled.messageBuffer(); - } - @Override public void handlerRemoved(ChannelHandlerContext ctx) throws Exception { removalThreadNames.add(Thread.currentThread().getName()); } @Override - public void inboundBufferUpdated( - ChannelHandlerContext ctx) throws Exception { - ctx.inboundMessageBuffer().clear(); + public void messageReceived(ChannelHandlerContext ctx, MessageList msgs) throws Exception { inboundThreadNames.add(Thread.currentThread().getName()); - ctx.fireInboundBufferUpdated(); + ctx.fireMessageReceived(msgs); } @Override - public void read(ChannelHandlerContext ctx) { - ctx.read(); - } - - @Override - public void flush(ChannelHandlerContext ctx, - ChannelPromise future) throws Exception { - ctx.outboundMessageBuffer().clear(); + public void write(ChannelHandlerContext ctx, MessageList msgs, ChannelPromise future) throws Exception { outboundThreadNames.add(Thread.currentThread().getName()); - ctx.flush(future); + ctx.write(msgs, future); } @Override @@ -413,8 +385,7 @@ public class LocalTransportThreadModelTest { * Converts integers into a binary stream. */ private static class MessageForwarder1 - extends ChannelDuplexHandler - implements ChannelInboundMessageHandler, ChannelOutboundByteHandler { + extends ChannelDuplexHandler { private final AtomicReference exception = new AtomicReference(); private volatile int inCnt; @@ -422,23 +393,7 @@ public class LocalTransportThreadModelTest { private volatile Thread t; @Override - public MessageBuf newInboundBuffer(ChannelHandlerContext ctx) throws Exception { - return Unpooled.messageBuffer(); - } - - @Override - public ByteBuf newOutboundBuffer(ChannelHandlerContext ctx) throws Exception { - return ChannelHandlerUtil.allocate(ctx); - } - - @Override - public void discardOutboundReadBytes(ChannelHandlerContext ctx) throws Exception { - // NOOP - } - - @Override - public void inboundBufferUpdated( - ChannelHandlerContext ctx) throws Exception { + public void messageReceived(ChannelHandlerContext ctx, MessageList msgs) throws Exception { Thread t = this.t; if (t == null) { this.t = Thread.currentThread(); @@ -446,55 +401,44 @@ public class LocalTransportThreadModelTest { Assert.assertSame(t, Thread.currentThread()); } - MessageBuf in = ctx.inboundMessageBuffer(); - ByteBuf out = ctx.nextInboundByteBuffer(); - - for (;;) { - Integer msg = in.poll(); - if (msg == null) { - break; - } + ByteBuf out = ctx.alloc().buffer(msgs.size() * 4); + for (int i = 0; i < msgs.size(); i ++) { + int m = ((Integer) msgs.get(i)).intValue(); int expected = inCnt ++; - Assert.assertEquals(expected, msg.intValue()); - if (out.maxCapacity() - out.writerIndex() < 4) { - // Next inbound buffer is full - attempt to flush some data. - ctx.fireInboundBufferUpdated(); - } - out.writeInt(msg); + Assert.assertEquals(expected, m); + out.writeInt(m); } - ctx.fireInboundBufferUpdated(); + ctx.fireMessageReceived(out); } @Override - public void read(ChannelHandlerContext ctx) { - ctx.read(); - } - - @Override - public void flush(ChannelHandlerContext ctx, - ChannelPromise future) throws Exception { + public void write(ChannelHandlerContext ctx, MessageList msgs, ChannelPromise future) throws Exception { Assert.assertSame(t, Thread.currentThread()); // Don't let the write request go to the server-side channel - just swallow. boolean swallow = this == ctx.pipeline().first(); - ByteBuf in = ctx.outboundByteBuffer(); - MessageBuf out = ctx.nextOutboundMessageBuffer(); - while (in.readableBytes() >= 4) { - int msg = in.readInt(); - int expected = outCnt ++; - Assert.assertEquals(expected, msg); - if (!swallow) { - out.add(msg); + for (int i = 0; i < msgs.size(); i ++) { + ByteBuf m = (ByteBuf) msgs.get(i); + int count = m.readableBytes() / 4; + MessageList out = MessageList.newInstance(count); + for (int j = 0; j < count; j ++) { + int actual = m.readInt(); + int expected = outCnt ++; + Assert.assertEquals(expected, actual); + if (!swallow) { + out.add(actual); + } + } + m.release(); + + if (swallow) { + future.setSuccess(); + } else { + ctx.write(out); } - } - in.discardSomeReadBytes(); - if (swallow) { - future.setSuccess(); - } else { - ctx.flush(future); } } @@ -510,9 +454,7 @@ public class LocalTransportThreadModelTest { /** * Converts a binary stream into integers. */ - private static class MessageForwarder2 - extends ChannelDuplexHandler - implements ChannelInboundByteHandler, ChannelOutboundMessageHandler { + private static class MessageForwarder2 extends ChannelDuplexHandler { private final AtomicReference exception = new AtomicReference(); private volatile int inCnt; @@ -520,25 +462,7 @@ public class LocalTransportThreadModelTest { private volatile Thread t; @Override - public ByteBuf newInboundBuffer( - ChannelHandlerContext ctx) throws Exception { - return ctx.alloc().buffer(); - } - - @Override - public void discardInboundReadBytes(ChannelHandlerContext ctx) throws Exception { - ctx.inboundByteBuffer().discardSomeReadBytes(); - } - - @Override - public MessageBuf newOutboundBuffer( - ChannelHandlerContext ctx) throws Exception { - return Unpooled.messageBuffer(); - } - - @Override - public void inboundBufferUpdated( - ChannelHandlerContext ctx) throws Exception { + public void messageReceived(ChannelHandlerContext ctx, MessageList msgs) throws Exception { Thread t = this.t; if (t == null) { this.t = Thread.currentThread(); @@ -546,49 +470,35 @@ public class LocalTransportThreadModelTest { Assert.assertSame(t, Thread.currentThread()); } - ByteBuf in = ctx.inboundByteBuffer(); - MessageBuf out = ctx.nextInboundMessageBuffer(); - while (in.readableBytes() >= 4) { - int msg = in.readInt(); - int expected = inCnt ++; - Assert.assertEquals(expected, msg); - out.add(msg); + for (int i = 0; i < msgs.size(); i ++) { + ByteBuf m = (ByteBuf) msgs.get(i); + int count = m.readableBytes() / 4; + MessageList out = MessageList.newInstance(count); + for (int j = 0; j < count; j ++) { + int actual = m.readInt(); + int expected = inCnt ++; + Assert.assertEquals(expected, actual); + out.add(actual); + } + m.release(); + ctx.fireMessageReceived(out); } - in.discardReadBytes(); - ctx.fireInboundBufferUpdated(); } @Override - public void read(ChannelHandlerContext ctx) { - ctx.read(); - } - - @Override - public void flush(final ChannelHandlerContext ctx, - ChannelPromise future) throws Exception { + public void write( + ChannelHandlerContext ctx, MessageList msgs, ChannelPromise promise) throws Exception { Assert.assertSame(t, Thread.currentThread()); - MessageBuf in = ctx.outboundMessageBuffer(); - ByteBuf out = ctx.nextOutboundByteBuffer(); - - for (;;) { - Integer msg = in.poll(); - if (msg == null) { - break; - } - + ByteBuf out = ctx.alloc().buffer(msgs.size() * 4); + for (int i = 0; i < msgs.size(); i ++) { + int m = (Integer) msgs.get(i); int expected = outCnt ++; - Assert.assertEquals(expected, msg.intValue()); - - if (out.maxCapacity() - out.writerIndex() < 4) { - // Next outbound buffer is full - attempt to flush some data. - ctx.flush(); - } - - out.writeInt(msg); + Assert.assertEquals(expected, m); + out.writeInt(m); } - ctx.flush(future); + ctx.write(out); } @Override @@ -603,9 +513,7 @@ public class LocalTransportThreadModelTest { /** * Simply forwards the received object to the next handler. */ - private static class MessageForwarder3 - extends ChannelDuplexHandler - implements ChannelInboundMessageHandler, ChannelOutboundMessageHandler { + private static class MessageForwarder3 extends ChannelDuplexHandler { private final AtomicReference exception = new AtomicReference(); private volatile int inCnt; @@ -613,17 +521,7 @@ public class LocalTransportThreadModelTest { private volatile Thread t; @Override - public MessageBuf newInboundBuffer(ChannelHandlerContext ctx) throws Exception { - return Unpooled.messageBuffer(); - } - - @Override - public MessageBuf newOutboundBuffer(ChannelHandlerContext ctx) throws Exception { - return Unpooled.messageBuffer(); - } - - @Override - public void inboundBufferUpdated(ChannelHandlerContext ctx) throws Exception { + public void messageReceived(ChannelHandlerContext ctx, MessageList msgs) throws Exception { Thread t = this.t; if (t == null) { this.t = Thread.currentThread(); @@ -631,44 +529,25 @@ public class LocalTransportThreadModelTest { Assert.assertSame(t, Thread.currentThread()); } - MessageBuf in = ctx.inboundMessageBuffer(); - MessageBuf out = ctx.nextInboundMessageBuffer(); - for (;;) { - Object msg = in.poll(); - if (msg == null) { - break; - } - + for (int i = 0; i < msgs.size(); i ++) { + int actual = (Integer) msgs.get(i); int expected = inCnt ++; - Assert.assertEquals(expected, msg); - out.add(msg); + Assert.assertEquals(expected, actual); } - ctx.fireInboundBufferUpdated(); + ctx.fireMessageReceived(msgs); } @Override - public void read(ChannelHandlerContext ctx) { - ctx.read(); - } - - @Override - public void flush(ChannelHandlerContext ctx, - ChannelPromise future) throws Exception { + public void write( + ChannelHandlerContext ctx, MessageList msgs, ChannelPromise promise) throws Exception { Assert.assertSame(t, Thread.currentThread()); - MessageBuf in = ctx.outboundMessageBuffer(); - MessageBuf out = ctx.nextOutboundMessageBuffer(); - for (;;) { - Object msg = in.poll(); - if (msg == null) { - break; - } - + for (int i = 0; i < msgs.size(); i ++) { + int actual = (Integer) msgs.get(i); int expected = outCnt ++; - Assert.assertEquals(expected, msg); - out.add(msg); + Assert.assertEquals(expected, actual); } - ctx.flush(future); + ctx.write(msgs, promise); } @Override @@ -683,9 +562,7 @@ public class LocalTransportThreadModelTest { /** * Discards all received messages. */ - private static class MessageDiscarder - extends ChannelDuplexHandler - implements ChannelInboundMessageHandler, ChannelOutboundMessageHandler { + private static class MessageDiscarder extends ChannelDuplexHandler { private final AtomicReference exception = new AtomicReference(); private volatile int inCnt; @@ -693,17 +570,7 @@ public class LocalTransportThreadModelTest { private volatile Thread t; @Override - public MessageBuf newInboundBuffer(ChannelHandlerContext ctx) throws Exception { - return Unpooled.messageBuffer(); - } - - @Override - public MessageBuf newOutboundBuffer(ChannelHandlerContext ctx) throws Exception { - return Unpooled.messageBuffer(); - } - - @Override - public void inboundBufferUpdated(ChannelHandlerContext ctx) throws Exception { + public void messageReceived(ChannelHandlerContext ctx, MessageList msgs) throws Exception { Thread t = this.t; if (t == null) { this.t = Thread.currentThread(); @@ -711,40 +578,24 @@ public class LocalTransportThreadModelTest { Assert.assertSame(t, Thread.currentThread()); } - MessageBuf in = ctx.inboundMessageBuffer(); - for (;;) { - Object msg = in.poll(); - if (msg == null) { - break; - } + for (int i = 0; i < msgs.size(); i ++) { + int actual = (Integer) msgs.get(i); int expected = inCnt ++; - Assert.assertEquals(expected, msg); + Assert.assertEquals(expected, actual); } } @Override - public void read(ChannelHandlerContext ctx) { - ctx.read(); - } - - @Override - public void flush(ChannelHandlerContext ctx, - ChannelPromise future) throws Exception { + public void write( + ChannelHandlerContext ctx, MessageList msgs, ChannelPromise promise) throws Exception { Assert.assertSame(t, Thread.currentThread()); - MessageBuf in = ctx.outboundMessageBuffer(); - MessageBuf out = ctx.nextOutboundMessageBuffer(); - for (;;) { - Object msg = in.poll(); - if (msg == null) { - break; - } - + for (int i = 0; i < msgs.size(); i ++) { + int actual = (Integer) msgs.get(i); int expected = outCnt ++; - Assert.assertEquals(expected, msg); - out.add(msg); + Assert.assertEquals(expected, actual); } - ctx.flush(future); + ctx.write(msgs, promise); } @Override diff --git a/transport/src/test/java/io/netty/channel/local/LocalTransportThreadModelTest2.java b/transport/src/test/java/io/netty/channel/local/LocalTransportThreadModelTest2.java index fba75ce135..174bf7e041 100644 --- a/transport/src/test/java/io/netty/channel/local/LocalTransportThreadModelTest2.java +++ b/transport/src/test/java/io/netty/channel/local/LocalTransportThreadModelTest2.java @@ -17,15 +17,14 @@ package io.netty.channel.local; import io.netty.bootstrap.Bootstrap; import io.netty.bootstrap.ServerBootstrap; -import io.netty.buffer.MessageBuf; import io.netty.channel.Channel; import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelHandler.Sharable; import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.ChannelInboundMessageHandlerAdapter; +import io.netty.channel.ChannelInboundHandlerAdapter; +import io.netty.channel.MessageList; import org.junit.Test; -import java.util.Iterator; import java.util.concurrent.atomic.AtomicInteger; import static org.junit.Assert.*; @@ -73,30 +72,11 @@ public class LocalTransportThreadModelTest2 { public void close(final Channel localChannel, final LocalHander localRegistrationHandler) { // we want to make sure we actually shutdown IN the event loop if (localChannel.eventLoop().inEventLoop()) { - MessageBuf outboundMessageBuffer = - localChannel.pipeline().outboundMessageBuffer(); - if (!outboundMessageBuffer.isEmpty()) { - System.err.println("NOT EMPTY TO SEND!"); - } - // Wait until all messages are flushed before closing the channel. if (localRegistrationHandler.lastWriteFuture != null) { localRegistrationHandler.lastWriteFuture.awaitUninterruptibly(); } - MessageBuf inboundMessageBuffer = - localChannel.pipeline().inboundMessageBuffer(); - if (!inboundMessageBuffer.isEmpty()) { - // sometimes we close the pipeline before everything on it has been notified/received. - // we want these messages, since they are in our queue. - Iterator iterator = inboundMessageBuffer.iterator(); - while (iterator.hasNext()) { - Object next = iterator.next(); - System.err.println("DEFERRED on close: " + next); - iterator.remove(); - } - } - localChannel.close(); return; } @@ -113,7 +93,7 @@ public class LocalTransportThreadModelTest2 { } @Sharable - static class LocalHander extends ChannelInboundMessageHandlerAdapter { + static class LocalHander extends ChannelInboundHandlerAdapter { private final String name; public volatile ChannelFuture lastWriteFuture; @@ -132,8 +112,9 @@ public class LocalTransportThreadModelTest2 { } @Override - public void messageReceived(ChannelHandlerContext ctx, Object msg) throws Exception { - count.incrementAndGet(); + public void messageReceived(ChannelHandlerContext ctx, MessageList msgs) throws Exception { + count.addAndGet(msgs.size()); + msgs.recycle(); } } } diff --git a/transport/src/test/java/io/netty/channel/local/LocalTransportThreadModelTest3.java b/transport/src/test/java/io/netty/channel/local/LocalTransportThreadModelTest3.java index ccc01297b2..dad52b2226 100644 --- a/transport/src/test/java/io/netty/channel/local/LocalTransportThreadModelTest3.java +++ b/transport/src/test/java/io/netty/channel/local/LocalTransportThreadModelTest3.java @@ -20,10 +20,11 @@ import io.netty.channel.Channel; import io.netty.channel.ChannelDuplexHandler; import io.netty.channel.ChannelHandler; import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.ChannelInboundMessageHandlerAdapter; +import io.netty.channel.ChannelInboundHandlerAdapter; import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelPromise; import io.netty.channel.EventLoopGroup; +import io.netty.channel.MessageList; import io.netty.util.concurrent.DefaultEventExecutorGroup; import io.netty.util.concurrent.DefaultThreadFactory; import io.netty.util.concurrent.EventExecutorGroup; @@ -50,8 +51,8 @@ public class LocalTransportThreadModelTest3 { ACTIVE, UNREGISTERED, REGISTERED, - INBOUND_BUFFER_UPDATED, - FLUSH, + MESSAGE_RECEIVED, + WRITE, READ } @@ -68,9 +69,10 @@ public class LocalTransportThreadModelTest3 { .childHandler(new ChannelInitializer() { @Override public void initChannel(LocalChannel ch) throws Exception { - ch.pipeline().addLast(new ChannelInboundMessageHandlerAdapter() { + ch.pipeline().addLast(new ChannelInboundHandlerAdapter() { @Override - public void messageReceived(ChannelHandlerContext ctx, Object msg) { + public void messageReceived( + ChannelHandlerContext ctx, MessageList msgs) throws Exception { // Discard } }); @@ -176,8 +178,8 @@ public class LocalTransportThreadModelTest3 { case EXCEPTION_CAUGHT: ch.pipeline().fireExceptionCaught(cause); break; - case INBOUND_BUFFER_UPDATED: - ch.pipeline().fireInboundBufferUpdated(); + case MESSAGE_RECEIVED: + ch.pipeline().fireMessageReceived(""); break; case READ_SUSPEND: ch.pipeline().fireChannelReadSuspended(); @@ -185,8 +187,8 @@ public class LocalTransportThreadModelTest3 { case USER_EVENT: ch.pipeline().fireUserEventTriggered(""); break; - case FLUSH: - ch.pipeline().flush(); + case WRITE: + ch.pipeline().write(""); break; case READ: ch.pipeline().read(); @@ -227,11 +229,11 @@ public class LocalTransportThreadModelTest3 { EventType[] events; if (inbound) { events = new EventType[] { - EventType.USER_EVENT, EventType.INBOUND_BUFFER_UPDATED, EventType.READ_SUSPEND, + EventType.USER_EVENT, EventType.MESSAGE_RECEIVED, EventType.READ_SUSPEND, EventType.EXCEPTION_CAUGHT}; } else { events = new EventType[] { - EventType.READ, EventType.FLUSH, EventType.EXCEPTION_CAUGHT }; + EventType.READ, EventType.WRITE, EventType.EXCEPTION_CAUGHT }; } Random random = new Random(); @@ -243,17 +245,7 @@ public class LocalTransportThreadModelTest3 { } @ChannelHandler.Sharable - private static final class EventForwarder extends ChannelDuplexHandler { - @Override - public void flush(ChannelHandlerContext ctx, ChannelPromise promise) throws Exception { - ctx.flush(promise); - } - - @Override - public void inboundBufferUpdated(ChannelHandlerContext ctx) throws Exception { - ctx.fireInboundBufferUpdated(); - } - } + private static final class EventForwarder extends ChannelDuplexHandler { } private static final class EventRecorder extends ChannelDuplexHandler { private final Queue events; @@ -304,16 +296,17 @@ public class LocalTransportThreadModelTest3 { } @Override - public void inboundBufferUpdated(ChannelHandlerContext ctx) throws Exception { + public void messageReceived(ChannelHandlerContext ctx, MessageList msgs) throws Exception { if (inbound) { - events.add(EventType.INBOUND_BUFFER_UPDATED); + events.add(EventType.MESSAGE_RECEIVED); } } @Override - public void flush(ChannelHandlerContext ctx, ChannelPromise promise) throws Exception { + public void write( + ChannelHandlerContext ctx, MessageList msgs, ChannelPromise promise) throws Exception { if (!inbound) { - events.add(EventType.FLUSH); + events.add(EventType.WRITE); } } diff --git a/transport/src/test/java/io/netty/channel/nio/NioDatagramChannelTest.java b/transport/src/test/java/io/netty/channel/nio/NioDatagramChannelTest.java index 283b37fd3b..fc35c993bc 100644 --- a/transport/src/test/java/io/netty/channel/nio/NioDatagramChannelTest.java +++ b/transport/src/test/java/io/netty/channel/nio/NioDatagramChannelTest.java @@ -17,11 +17,11 @@ package io.netty.channel.nio; import io.netty.bootstrap.Bootstrap; import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.ChannelInboundMessageHandlerAdapter; +import io.netty.channel.ChannelInboundHandlerAdapter; import io.netty.channel.ChannelOption; +import io.netty.channel.MessageList; import io.netty.channel.group.DefaultChannelGroup; import io.netty.channel.socket.DatagramChannel; -import io.netty.channel.socket.DatagramPacket; import io.netty.channel.socket.nio.NioDatagramChannel; import org.junit.Assert; import org.junit.Test; @@ -43,10 +43,10 @@ public class NioDatagramChannelTest { Bootstrap udpBootstrap = new Bootstrap(); udpBootstrap.group(group).channel(NioDatagramChannel.class) .option(ChannelOption.SO_BROADCAST, true) - .handler(new ChannelInboundMessageHandlerAdapter() { + .handler(new ChannelInboundHandlerAdapter() { @Override - public void messageReceived(ChannelHandlerContext ctx, DatagramPacket msg) - throws Exception { + public void messageReceived( + ChannelHandlerContext ctx, MessageList msgs) throws Exception { // noop } });