├── .gitignore ├── LICENSE ├── README.md ├── TOC.md ├── chapter1 ├── .gitignore ├── .project ├── README.md ├── build.gradle └── src │ └── main │ └── java │ ├── chapter1 │ ├── recipe1 │ │ ├── AsynchTcpServer.java │ │ ├── TcpClient.java │ │ ├── TcpClientLambdaHandler.java │ │ └── TcpServerHandler.java │ ├── recipe2 │ │ ├── TcpClient.java │ │ └── TcpClientHandler.java │ ├── recipe3 │ │ ├── TcpClient.java │ │ ├── TcpClientHandler.java │ │ ├── TcpServer.java │ │ └── TcpServerHandler.java │ ├── recipe4 │ │ ├── TcpClientHandler.java │ │ ├── TcpClientPipe.java │ │ ├── TcpServerInboundHandler.java │ │ ├── TcpServerOutboundHandler.java │ │ └── TcpServerPipe.java │ └── recipe6 │ │ ├── DataPipelineProcessingServer.java │ │ └── DataProcessingPipeline.java │ ├── log4j.properties │ └── netty │ └── cookbook │ └── common │ ├── BootstrapTemplate.java │ ├── CallbackProcessor.java │ ├── CharPool.java │ ├── FileUtils.java │ ├── LogUtil.java │ ├── StringPool.java │ ├── StringUtil.java │ ├── TcpChannelHandler.java │ └── UrlUtil.java ├── chapter2 ├── .gitignore ├── .project ├── README.md ├── build.gradle ├── data │ └── text-file.txt ├── lib │ └── netty-codec-ftp-0.2-SNAPSHOT.jar ├── src │ └── main │ │ ├── avro │ │ └── mail.avpr │ │ └── java │ │ ├── avro │ │ ├── Mail.java │ │ └── Message.java │ │ ├── chapter2 │ │ ├── recipe10 │ │ │ ├── ClientAvroRPC.java │ │ │ └── ProxyServerAvroRPC.java │ │ ├── recipe11 │ │ │ └── HttpDownloader.java │ │ ├── recipe2 │ │ │ ├── Receiver.java │ │ │ └── Sender.java │ │ ├── recipe3 │ │ │ ├── PurchaseClient.java │ │ │ ├── PurchaseClientHandler.java │ │ │ ├── PurchaseData.java │ │ │ ├── PurchaseDataDecoder.java │ │ │ ├── PurchaseDataEncoder.java │ │ │ └── PurchaseServer.java │ │ ├── recipe4 │ │ │ └── MultiSocketServer.java │ │ ├── recipe6 │ │ │ └── NettyMonitorIO.java │ │ ├── recipe7 │ │ │ ├── HeartBeatHandler.java │ │ │ ├── ImportantServer.java │ │ │ └── ServerHealthChecker.java │ │ ├── recipe8 │ │ │ ├── SimpleSctpClient.java │ │ │ ├── SimpleSctpClientHandler.java │ │ │ ├── SimpleSctpServer.java │ │ │ └── SimpleSctpServerHandler.java │ │ └── recipe9 │ │ │ ├── FileReceiver.java │ │ │ └── SimpleServerFTP.java │ │ ├── log4j.properties │ │ └── netty │ │ └── cookbook │ │ └── common │ │ ├── BootstrapTemplate.java │ │ ├── CallbackProcessor.java │ │ ├── CharPool.java │ │ ├── FileUtils.java │ │ ├── LogUtil.java │ │ ├── StringPool.java │ │ ├── StringUtil.java │ │ ├── TcpChannelHandler.java │ │ └── UrlUtil.java └── tools │ └── avro-tools-1.7.7.jar ├── chapter3 ├── .gitignore ├── .project ├── README.md ├── build.gradle ├── configs │ ├── redis-connection-pool-configs.json │ └── regexes.yaml ├── lib │ ├── DateAdapterJ-1.1.3-20141216.175259-8.jar │ ├── RestExpress-0.11.0-20150113.201733-1.jar │ ├── RestExpress-Common-0.11.0-20150113.201714-1.jar │ └── alpn-boot-8.1.0.v20141016.jar └── src │ └── main │ ├── java │ ├── chapter3 │ │ ├── recipe1 │ │ │ ├── HttpEventRoutingHandler.java │ │ │ ├── HttpServerWithRouter.java │ │ │ └── UriMatcher.java │ │ ├── recipe2 │ │ │ ├── DispatcherServletChannelInitializer.java │ │ │ ├── HelloController.java │ │ │ ├── HttpServerSpringMVC.java │ │ │ ├── ServletNettyChannelHandler.java │ │ │ ├── TemplateConfiguration.java │ │ │ └── WebConfig.java │ │ ├── recipe3 │ │ │ ├── HttpFileServer.java │ │ │ └── HttpStaticFileServerHandler.java │ │ ├── recipe4 │ │ │ ├── NettyHttpServerWithCORS.java │ │ │ └── SimpleCORSHandler.java │ │ ├── recipe5 │ │ │ ├── HttpServerSPDY.java │ │ │ ├── SpdyOrHttpHandler.java │ │ │ └── SpdyServerHandler.java │ │ └── recipe6 │ │ │ ├── FunctionPipeline.java │ │ │ ├── FunctionsChannelHandler.java │ │ │ ├── LambdaHttpServer.java │ │ │ ├── SimpleHttpRequest.java │ │ │ ├── SimpleHttpResponse.java │ │ │ └── functions │ │ │ ├── Decorator.java │ │ │ ├── Filter.java │ │ │ ├── FinalProcessor.java │ │ │ └── Processor.java │ ├── log4j.properties │ ├── netty │ │ └── cookbook │ │ │ └── common │ │ │ ├── CallbackActor.java │ │ │ ├── CallbackProcessor.java │ │ │ ├── CharPool.java │ │ │ ├── FileUtils.java │ │ │ ├── JsOptimizerUtil.java │ │ │ ├── LogUtil.java │ │ │ ├── NashornEngineUtil.java │ │ │ ├── NettyServerUtil.java │ │ │ ├── StringPool.java │ │ │ ├── StringUtil.java │ │ │ ├── TcpChannelHandler.java │ │ │ ├── UrlUtil.java │ │ │ ├── http │ │ │ ├── BasicHttpResponseHandler.java │ │ │ ├── ContentTypePool.java │ │ │ ├── HttpEventHandler.java │ │ │ ├── HttpEventProcessor.java │ │ │ ├── HttpOutputResource.java │ │ │ ├── HttpRequestData.java │ │ │ ├── HttpRequestEvent.java │ │ │ └── NettyHttpUtil.java │ │ │ └── redis │ │ │ ├── RedisCommand.java │ │ │ ├── RedisConnectionPoolConfig.java │ │ │ └── RedisInfo.java │ └── rfx │ │ └── server │ │ └── util │ │ └── ua │ │ ├── Client.java │ │ ├── Device.java │ │ ├── DeviceParser.java │ │ ├── OS.java │ │ ├── OSParser.java │ │ ├── Parser.java │ │ ├── UserAgent.java │ │ └── UserAgentParser.java │ └── resources │ └── templates │ ├── cors.html │ ├── hello-view.html │ └── js │ └── script.js ├── chapter4 ├── .gitignore ├── .project ├── README.md ├── build.gradle ├── configs │ ├── redis-connection-pool-configs.json │ └── regexes.yaml └── src │ └── main │ └── java │ ├── chapter4 │ ├── recipe1 │ │ └── WebSocketServer.java │ ├── recipe2 │ │ └── RealtimeWebSocketIO.java │ ├── recipe3 │ │ └── ChatServerWithSTOMP.java │ └── recipe4 │ │ ├── NettyRxJavaServer.java │ │ └── RealtimeWidgetServer.java │ ├── log4j.properties │ ├── netty │ └── cookbook │ │ └── common │ │ ├── BootstrapTemplate.java │ │ ├── CallbackProcessor.java │ │ ├── CharPool.java │ │ ├── FileUtils.java │ │ ├── LogUtil.java │ │ ├── StringPool.java │ │ ├── StringUtil.java │ │ ├── TcpChannelHandler.java │ │ ├── UrlUtil.java │ │ ├── http │ │ ├── ContentTypePool.java │ │ ├── HttpOutputResource.java │ │ ├── HttpRequestData.java │ │ ├── HttpRequestEvent.java │ │ └── NettyHttpUtil.java │ │ └── redis │ │ ├── RedisCommand.java │ │ ├── RedisConnectionPoolConfig.java │ │ └── RedisInfo.java │ └── rfx │ └── server │ └── util │ └── ua │ ├── Client.java │ ├── Device.java │ ├── DeviceParser.java │ ├── OS.java │ ├── OSParser.java │ ├── Parser.java │ ├── UserAgent.java │ └── UserAgentParser.java ├── chapter5 ├── .gitignore ├── .project ├── README.md ├── build.gradle └── src │ └── main │ └── java │ ├── chapter4 │ ├── recipe1 │ │ └── WebSocketServer.java │ ├── recipe2 │ │ └── RealtimeWebSocketIO.java │ ├── recipe3 │ │ └── ChatServerWithSTOMP.java │ └── recipe4 │ │ └── RealtimeWidgetServer.java │ ├── log4j.properties │ ├── netty │ └── cookbook │ │ └── common │ │ ├── BootstrapTemplate.java │ │ ├── CallbackProcessor.java │ │ ├── CharPool.java │ │ ├── FileUtils.java │ │ ├── LogUtil.java │ │ ├── StringPool.java │ │ ├── StringUtil.java │ │ ├── TcpChannelHandler.java │ │ ├── UrlUtil.java │ │ ├── http │ │ ├── ContentTypePool.java │ │ ├── HttpOutputResource.java │ │ ├── HttpRequestData.java │ │ ├── HttpRequestEvent.java │ │ └── NettyHttpUtil.java │ │ └── redis │ │ ├── RedisCommand.java │ │ ├── RedisConnectionPoolConfig.java │ │ └── RedisInfo.java │ └── rfx │ └── server │ └── util │ └── ua │ ├── Client.java │ ├── Device.java │ ├── DeviceParser.java │ ├── OS.java │ ├── OSParser.java │ ├── Parser.java │ ├── UserAgent.java │ └── UserAgentParser.java ├── chapter6 ├── .gitignore ├── .project ├── README.md ├── build.gradle └── src │ └── main │ └── java │ ├── chapter4 │ ├── recipe1 │ │ └── WebSocketServer.java │ ├── recipe2 │ │ └── RealtimeWebSocketIO.java │ ├── recipe3 │ │ └── ChatServerWithSTOMP.java │ └── recipe4 │ │ └── RealtimeWidgetServer.java │ ├── log4j.properties │ ├── netty │ └── cookbook │ │ └── common │ │ ├── BootstrapTemplate.java │ │ ├── CallbackProcessor.java │ │ ├── CharPool.java │ │ ├── FileUtils.java │ │ ├── LogUtil.java │ │ ├── StringPool.java │ │ ├── StringUtil.java │ │ ├── TcpChannelHandler.java │ │ ├── UrlUtil.java │ │ ├── http │ │ ├── ContentTypePool.java │ │ ├── HttpOutputResource.java │ │ ├── HttpRequestData.java │ │ ├── HttpRequestEvent.java │ │ └── NettyHttpUtil.java │ │ └── redis │ │ ├── RedisCommand.java │ │ ├── RedisConnectionPoolConfig.java │ │ └── RedisInfo.java │ └── rfx │ └── server │ └── util │ └── ua │ ├── Client.java │ ├── Device.java │ ├── DeviceParser.java │ ├── OS.java │ ├── OSParser.java │ ├── Parser.java │ ├── UserAgent.java │ └── UserAgentParser.java ├── chapter7 ├── .gitignore ├── .project ├── README.md ├── build.gradle └── src │ └── main │ └── java │ ├── chapter7 │ └── recipe1 │ │ ├── client │ │ ├── Http2Client.java │ │ ├── Http2ClientInitializer.java │ │ ├── Http2SettingsHandler.java │ │ └── HttpResponseHandler.java │ │ └── server │ │ ├── HelloWorldHttp1Handler.java │ │ ├── HelloWorldHttp2Handler.java │ │ ├── Http2OrHttpHandler.java │ │ ├── Http2Server.java │ │ └── Http2ServerInitializer.java │ ├── log4j.properties │ ├── netty │ └── cookbook │ │ └── common │ │ ├── BootstrapTemplate.java │ │ ├── CallbackProcessor.java │ │ ├── CharPool.java │ │ ├── FileUtils.java │ │ ├── Http2Util.java │ │ ├── LogUtil.java │ │ ├── StringPool.java │ │ ├── StringUtil.java │ │ ├── UrlUtil.java │ │ └── redis │ │ ├── RedisCommand.java │ │ ├── RedisConnectionPoolConfig.java │ │ └── RedisInfo.java │ └── rfx │ └── server │ └── util │ └── ua │ ├── Client.java │ ├── Device.java │ ├── DeviceParser.java │ ├── OS.java │ ├── OSParser.java │ ├── Parser.java │ ├── UserAgent.java │ └── UserAgentParser.java ├── chapter8 ├── .gitignore ├── .project ├── README.md ├── build.gradle └── src │ └── main │ └── java │ ├── chapter4 │ ├── recipe1 │ │ └── WebSocketServer.java │ ├── recipe2 │ │ └── RealtimeWebSocketIO.java │ ├── recipe3 │ │ └── ChatServerWithSTOMP.java │ └── recipe4 │ │ └── RealtimeWidgetServer.java │ ├── log4j.properties │ ├── netty │ └── cookbook │ │ └── common │ │ ├── BootstrapTemplate.java │ │ ├── CallbackProcessor.java │ │ ├── CharPool.java │ │ ├── FileUtils.java │ │ ├── LogUtil.java │ │ ├── StringPool.java │ │ ├── StringUtil.java │ │ ├── TcpChannelHandler.java │ │ ├── UrlUtil.java │ │ ├── http │ │ ├── ContentTypePool.java │ │ ├── HttpOutputResource.java │ │ ├── HttpRequestData.java │ │ ├── HttpRequestEvent.java │ │ └── NettyHttpUtil.java │ │ └── redis │ │ ├── RedisCommand.java │ │ ├── RedisConnectionPoolConfig.java │ │ └── RedisInfo.java │ └── rfx │ └── server │ └── util │ └── ua │ ├── Client.java │ ├── Device.java │ ├── DeviceParser.java │ ├── OS.java │ ├── OSParser.java │ ├── Parser.java │ ├── UserAgent.java │ └── UserAgentParser.java ├── chapter9 ├── .gitignore ├── .project ├── README.md ├── build.gradle └── src │ └── main │ └── java │ ├── chapter4 │ ├── recipe1 │ │ └── WebSocketServer.java │ ├── recipe2 │ │ └── RealtimeWebSocketIO.java │ ├── recipe3 │ │ └── ChatServerWithSTOMP.java │ └── recipe4 │ │ └── RealtimeWidgetServer.java │ ├── log4j.properties │ ├── netty │ └── cookbook │ │ └── common │ │ ├── BootstrapTemplate.java │ │ ├── CallbackProcessor.java │ │ ├── CharPool.java │ │ ├── FileUtils.java │ │ ├── LogUtil.java │ │ ├── StringPool.java │ │ ├── StringUtil.java │ │ ├── TcpChannelHandler.java │ │ ├── UrlUtil.java │ │ ├── http │ │ ├── ContentTypePool.java │ │ ├── HttpOutputResource.java │ │ ├── HttpRequestData.java │ │ ├── HttpRequestEvent.java │ │ └── NettyHttpUtil.java │ │ └── redis │ │ ├── RedisCommand.java │ │ ├── RedisConnectionPoolConfig.java │ │ └── RedisInfo.java │ └── rfx │ └── server │ └── util │ └── ua │ ├── Client.java │ ├── Device.java │ ├── DeviceParser.java │ ├── OS.java │ ├── OSParser.java │ ├── Parser.java │ ├── UserAgent.java │ └── UserAgentParser.java └── netty-cookbook-java-src ├── .gitignore ├── .project ├── README.txt ├── build.gradle ├── configs ├── redis-connection-pool-configs.json └── regexes.yaml ├── data ├── text-file.txt └── www.mc2ads.com.html ├── lib ├── mongodb-async-driver-2.0.1.jar └── netty-codec-ftp-0.2-SNAPSHOT.jar ├── src ├── main │ ├── avro │ │ └── mail.avpr │ └── java │ │ ├── avro │ │ ├── Mail.java │ │ └── Message.java │ │ ├── log4j.properties │ │ ├── netty │ │ └── cookbook │ │ │ ├── chapter1 │ │ │ ├── recipe1 │ │ │ │ ├── AsynchTcpServer.java │ │ │ │ ├── TcpClient.java │ │ │ │ ├── TcpClientLambdaHandler.java │ │ │ │ └── TcpServerHandler.java │ │ │ ├── recipe2 │ │ │ │ ├── TcpClient.java │ │ │ │ └── TcpClientHandler.java │ │ │ ├── recipe3 │ │ │ │ ├── TcpClient.java │ │ │ │ ├── TcpClientHandler.java │ │ │ │ ├── TcpServer.java │ │ │ │ └── TcpServerHandler.java │ │ │ ├── recipe4 │ │ │ │ ├── TcpClientHandler.java │ │ │ │ ├── TcpClientPipe.java │ │ │ │ ├── TcpServerInboundHandler.java │ │ │ │ ├── TcpServerOutboundHandler.java │ │ │ │ └── TcpServerPipe.java │ │ │ └── recipe6 │ │ │ │ ├── DataPipelineProcessingServer.java │ │ │ │ └── DataProcessingPipeline.java │ │ │ ├── chapter2 │ │ │ ├── recipe10 │ │ │ │ ├── ClientAvroRPC.java │ │ │ │ └── ProxyServerAvroRPC.java │ │ │ ├── recipe11 │ │ │ │ └── HttpDownloader.java │ │ │ ├── recipe2 │ │ │ │ ├── Receiver.java │ │ │ │ └── Sender.java │ │ │ ├── recipe3 │ │ │ │ ├── PurchaseClient.java │ │ │ │ ├── PurchaseClientHandler.java │ │ │ │ ├── PurchaseDataDecoder.java │ │ │ │ ├── PurchaseDataEncoder.java │ │ │ │ └── PurchaseServer.java │ │ │ ├── recipe4 │ │ │ │ └── MultiSocketServer.java │ │ │ ├── recipe6 │ │ │ │ └── NettyMonitorIO.java │ │ │ ├── recipe7 │ │ │ │ ├── HeartBeatHandler.java │ │ │ │ ├── ImportantServer.java │ │ │ │ └── ServerHealthChecker.java │ │ │ ├── recipe8 │ │ │ │ ├── SimpleSctpClient.java │ │ │ │ ├── SimpleSctpClientHandler.java │ │ │ │ ├── SimpleSctpServer.java │ │ │ │ └── SimpleSctpServerHandler.java │ │ │ └── recipe9 │ │ │ │ ├── FileReceiver.java │ │ │ │ └── SimpleServerFTP.java │ │ │ ├── chapter3 │ │ │ └── recipe1 │ │ │ │ └── Echo.java │ │ │ ├── chapter4 │ │ │ └── recipe5 │ │ │ │ ├── PubSubDemo.java │ │ │ │ ├── SocialAnalyticUpdater.java │ │ │ │ └── WebUrl.java │ │ │ ├── chapter8 │ │ │ └── recipe3 │ │ │ │ ├── HttpEventProcessingHandler.java │ │ │ │ ├── HttpServer.java │ │ │ │ └── PublicHttpServerInitializer.java │ │ │ └── common │ │ │ ├── BootstrapTemplate.java │ │ │ ├── CallbackActor.java │ │ │ ├── CallbackProcessor.java │ │ │ ├── CharPool.java │ │ │ ├── FileUtils.java │ │ │ ├── LogUtil.java │ │ │ ├── StringPool.java │ │ │ ├── StringUtil.java │ │ │ ├── TcpChannelHandler.java │ │ │ ├── UrlUtil.java │ │ │ ├── http │ │ │ ├── ContentTypePool.java │ │ │ ├── HttpOutputResource.java │ │ │ ├── HttpRequestData.java │ │ │ ├── HttpRequestEvent.java │ │ │ └── NettyHttpUtil.java │ │ │ ├── model │ │ │ └── PurchaseData.java │ │ │ ├── redis │ │ │ ├── RedisCommand.java │ │ │ ├── RedisConnectionPoolConfig.java │ │ │ └── RedisInfo.java │ │ │ └── tcp │ │ │ └── SimpleTcpServer.java │ │ └── rfx │ │ └── server │ │ └── util │ │ └── ua │ │ ├── Client.java │ │ ├── Device.java │ │ ├── DeviceParser.java │ │ ├── OS.java │ │ ├── OSParser.java │ │ ├── Parser.java │ │ ├── UserAgent.java │ │ └── UserAgentParser.java └── test │ └── java │ └── classic │ └── tcp │ ├── TCPClient.java │ └── TCPServer.java └── tools └── avro-tools-1.7.7.jar /.gitignore: -------------------------------------------------------------------------------- 1 | *.class 2 | 3 | # Mobile Tools for Java (J2ME) 4 | .mtj.tmp/ 5 | 6 | # Package Files # 7 | *.war 8 | *.ear 9 | 10 | # ignore the gradle metadata and build folder 11 | **/bin/ 12 | **/build/ 13 | **/build/ 14 | **/.gradle/ 15 | **/.settings/ 16 | *.classpath 17 | 18 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 19 | hs_err_pid* 20 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Netty Cookbook 2 | 3 | Download pdf at this link 4 | https://tantrieuf31.blogspot.com/2019/04/netty-cookbook.html 5 | 6 | ## Book Source Code 7 | 8 | The MIT License (MIT) 9 | Copyright (c) 2015 Trieu Nguyen 10 | 11 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 16 | -------------------------------------------------------------------------------- /chapter1/.gitignore: -------------------------------------------------------------------------------- 1 | /bin/ 2 | /build/ 3 | -------------------------------------------------------------------------------- /chapter1/.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | NettyCookbook-chapter1 4 | 5 | 6 | 7 | 8 | 9 | org.eclipse.jdt.core.javabuilder 10 | 11 | 12 | 13 | 14 | 15 | org.springsource.ide.eclipse.gradle.core.nature 16 | org.eclipse.jdt.core.javanature 17 | 18 | 19 | -------------------------------------------------------------------------------- /chapter1/README.md: -------------------------------------------------------------------------------- 1 | Netty Cookbook - chapter 1 code -------------------------------------------------------------------------------- /chapter1/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'java' 2 | apply plugin: 'eclipse' 3 | 4 | sourceCompatibility = 1.8 5 | 6 | version = '1.0' 7 | 8 | repositories { 9 | mavenCentral() 10 | } 11 | 12 | dependencies { 13 | compile ( 14 | // common 15 | 'io.netty:netty-all:4.0.25.Final' 16 | ,'commons-io:commons-io:2.4' 17 | ,'org.apache.commons:commons-lang3:3.3.2' 18 | ,'log4j:log4j:1.2.17' 19 | ,'org.slf4j:slf4j-log4j12:1.7.7' 20 | 21 | ,'com.google.code.gson:gson:2.3' 22 | ,'com.google.guava:guava:18.0' 23 | 24 | ) 25 | testCompile group: 'junit', name: 'junit', version: '4.11' 26 | } -------------------------------------------------------------------------------- /chapter1/src/main/java/chapter1/recipe4/TcpServerInboundHandler.java: -------------------------------------------------------------------------------- 1 | package chapter1.recipe4; 2 | 3 | import io.netty.channel.ChannelHandler.Sharable; 4 | import io.netty.channel.ChannelHandlerContext; 5 | import io.netty.channel.ChannelInboundHandlerAdapter; 6 | import io.netty.util.ReferenceCountUtil; 7 | 8 | /** 9 | * Handler implementation for the TCP server. 10 | */ 11 | @Sharable 12 | public class TcpServerInboundHandler extends ChannelInboundHandlerAdapter { 13 | 14 | 15 | @Override 16 | public void channelRead(ChannelHandlerContext ctx, Object msg) { 17 | try { 18 | System.out.println("TcpServerInboundHandler"); 19 | StringBuilder s = new StringBuilder(); 20 | s.append("Ok TCP client, TcpServerInboundHandler got your message \"").append(msg).append("\""); 21 | ctx.write(s); 22 | } finally { 23 | ReferenceCountUtil.release(msg); 24 | } 25 | } 26 | 27 | @Override 28 | public void channelReadComplete(ChannelHandlerContext ctx) { 29 | ctx.flush(); 30 | } 31 | 32 | @Override 33 | public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { 34 | // Close the connection when an exception is raised. 35 | cause.printStackTrace(); 36 | ctx.close(); 37 | } 38 | } -------------------------------------------------------------------------------- /chapter1/src/main/java/chapter1/recipe4/TcpServerOutboundHandler.java: -------------------------------------------------------------------------------- 1 | package chapter1.recipe4; 2 | 3 | import io.netty.channel.ChannelHandler.Sharable; 4 | import io.netty.channel.ChannelHandlerContext; 5 | import io.netty.channel.ChannelOutboundHandlerAdapter; 6 | import io.netty.util.concurrent.Future; 7 | import io.netty.util.concurrent.GenericFutureListener; 8 | 9 | /** 10 | * Handler implementation for the TCP server. 11 | */ 12 | @Sharable 13 | public class TcpServerOutboundHandler extends ChannelOutboundHandlerAdapter { 14 | @Override 15 | public void flush(ChannelHandlerContext ctx) throws Exception { 16 | super.flush(ctx); 17 | ctx.close().addListener(new GenericFutureListener>() { 18 | @Override 19 | public void operationComplete(Future future) 20 | throws Exception { 21 | System.out.println("close connection: "+future.isSuccess()); 22 | } 23 | }); 24 | } 25 | 26 | @Override 27 | public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { 28 | // Close the connection when an exception is raised. 29 | cause.printStackTrace(); 30 | ctx.close(); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /chapter1/src/main/java/chapter1/recipe6/DataPipelineProcessingServer.java: -------------------------------------------------------------------------------- 1 | package chapter1.recipe6; 2 | 3 | import io.netty.bootstrap.ServerBootstrap; 4 | import io.netty.channel.Channel; 5 | import io.netty.channel.ChannelFuture; 6 | import io.netty.channel.ChannelOption; 7 | import io.netty.channel.EventLoopGroup; 8 | import io.netty.channel.nio.NioEventLoopGroup; 9 | import io.netty.channel.socket.nio.NioServerSocketChannel; 10 | import io.netty.handler.logging.LogLevel; 11 | import io.netty.handler.logging.LoggingHandler; 12 | 13 | public class DataPipelineProcessingServer { 14 | static final int PORT = 8007; 15 | 16 | public static void main(String[] args) throws Exception{ 17 | // Configure the server. 18 | EventLoopGroup bossGroup = new NioEventLoopGroup(1); 19 | EventLoopGroup workerGroup = new NioEventLoopGroup(); 20 | try { 21 | ServerBootstrap b = new ServerBootstrap(); 22 | b.group(bossGroup, workerGroup) 23 | .channel(NioServerSocketChannel.class) 24 | .option(ChannelOption.SO_BACKLOG, 100) 25 | .handler(new LoggingHandler(LogLevel.INFO)) 26 | .childHandler(new DataProcessingPipeline()); 27 | 28 | // Start the server. 29 | ChannelFuture f = b.bind(PORT).sync(); 30 | Channel channel = f.channel(); 31 | 32 | // Wait until the server socket is closed. 33 | channel.closeFuture().sync(); 34 | } finally { 35 | // Shut down all event loops to terminate all threads. 36 | bossGroup.shutdownGracefully(); 37 | workerGroup.shutdownGracefully(); 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /chapter1/src/main/java/log4j.properties: -------------------------------------------------------------------------------- 1 | # Root logger option 2 | log4j.rootLogger=INFO, stdout 3 | 4 | # Redirect log messages to console 5 | log4j.appender.stdout=org.apache.log4j.ConsoleAppender 6 | log4j.appender.stdout.Target=System.out 7 | log4j.appender.stdout.layout=org.apache.log4j.PatternLayout 8 | log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n 9 | 10 | # Redirect log messages to a log file, support file rolling. 11 | log4j.appender.file=org.apache.log4j.RollingFileAppender 12 | log4j.appender.file.File=./log/java-cookbook-demo 13 | log4j.appender.file.MaxFileSize=5MB 14 | log4j.appender.file.MaxBackupIndex=10 15 | log4j.appender.file.layout=org.apache.log4j.PatternLayout 16 | log4j.appender.file.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n -------------------------------------------------------------------------------- /chapter1/src/main/java/netty/cookbook/common/CallbackProcessor.java: -------------------------------------------------------------------------------- 1 | package netty.cookbook.common; 2 | 3 | @FunctionalInterface 4 | public interface CallbackProcessor { 5 | public void process(Object obj); 6 | } -------------------------------------------------------------------------------- /chapter1/src/main/java/netty/cookbook/common/CharPool.java: -------------------------------------------------------------------------------- 1 | package netty.cookbook.common; 2 | 3 | public class CharPool { 4 | 5 | public static final char AMPERSAND = '&'; 6 | 7 | public static final char APOSTROPHE = '\''; 8 | 9 | public static final char AT = '@'; 10 | 11 | public static final char BACK_SLASH = '\\'; 12 | 13 | public static final char CLOSE_BRACKET = ']'; 14 | 15 | public static final char CLOSE_CURLY_BRACE = '}'; 16 | 17 | public static final char CLOSE_PARENTHESIS = ')'; 18 | 19 | public static final char COLON = ':'; 20 | 21 | public static final char COMMA = ','; 22 | 23 | public static final char DASH = '-'; 24 | 25 | public static final char EQUAL = '='; 26 | 27 | public static final char GREATER_THAN = '>'; 28 | 29 | public static final char FORWARD_SLASH = '/'; 30 | 31 | public static final char LESS_THAN = '<'; 32 | 33 | public static final char LOWER_CASE_E = 'e'; 34 | 35 | public static final char MINUS = '-'; 36 | 37 | public static final char NEW_LINE = '\n'; 38 | 39 | public static final char OPEN_BRACKET = '['; 40 | 41 | public static final char OPEN_CURLY_BRACE = '{'; 42 | 43 | public static final char OPEN_PARENTHESIS = '('; 44 | 45 | public static final char PERCENT = '%'; 46 | 47 | public static final char PERIOD = '.'; 48 | 49 | public static final char PIPE = '|'; 50 | 51 | public static final char PLUS = '+'; 52 | 53 | public static final char POUND = '#'; 54 | 55 | public static final char QUESTION = '?'; 56 | 57 | public static final char QUOTE = '\"'; 58 | 59 | public static final char RETURN = '\r'; 60 | 61 | public static final char SEMICOLON = ';'; 62 | 63 | public static final char SLASH = FORWARD_SLASH; 64 | 65 | public static final char SPACE = ' '; 66 | 67 | public static final char STAR = '*'; 68 | 69 | public static final char TILDE = '~'; 70 | 71 | public static final char UNDERLINE = '_'; 72 | 73 | public static final char UPPER_CASE_E = 'E'; 74 | 75 | public static final char TAB = '\t'; 76 | 77 | } 78 | -------------------------------------------------------------------------------- /chapter1/src/main/java/netty/cookbook/common/LogUtil.java: -------------------------------------------------------------------------------- 1 | package netty.cookbook.common; 2 | 3 | public class LogUtil { 4 | 5 | public static void println(Object obj){ 6 | System.out.println(obj); 7 | } 8 | 9 | public static void println(String obj){ 10 | System.out.println(obj); 11 | } 12 | 13 | 14 | } 15 | -------------------------------------------------------------------------------- /chapter1/src/main/java/netty/cookbook/common/TcpChannelHandler.java: -------------------------------------------------------------------------------- 1 | package netty.cookbook.common; 2 | 3 | import io.netty.channel.ChannelHandlerContext; 4 | 5 | @FunctionalInterface 6 | public interface TcpChannelHandler { 7 | public void process(ChannelHandlerContext ctx, Object msg); 8 | } 9 | -------------------------------------------------------------------------------- /chapter1/src/main/java/netty/cookbook/common/UrlUtil.java: -------------------------------------------------------------------------------- 1 | package netty.cookbook.common; 2 | 3 | import java.net.MalformedURLException; 4 | import java.net.URL; 5 | 6 | public class UrlUtil { 7 | public final static String REGEX_FOR_ROOT_DOMAIN = ".*\\.(?=.*\\.)"; 8 | 9 | public static String getRootDomain(String fullUrl) throws MalformedURLException{ 10 | return new URL(fullUrl).getHost().replaceAll(REGEX_FOR_ROOT_DOMAIN, ""); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /chapter2/.gitignore: -------------------------------------------------------------------------------- 1 | /bin/ 2 | /build/ 3 | -------------------------------------------------------------------------------- /chapter2/.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | NettyCookbook-chapter2 4 | 5 | 6 | 7 | 8 | 9 | org.eclipse.jdt.core.javabuilder 10 | 11 | 12 | 13 | 14 | 15 | org.springsource.ide.eclipse.gradle.core.nature 16 | org.eclipse.jdt.core.javanature 17 | 18 | 19 | -------------------------------------------------------------------------------- /chapter2/README.md: -------------------------------------------------------------------------------- 1 | Netty Cookbook - chapter 2 code -------------------------------------------------------------------------------- /chapter2/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'java' 2 | apply plugin: 'eclipse' 3 | 4 | sourceCompatibility = 1.8 5 | 6 | version = '1.0' 7 | 8 | repositories { 9 | mavenCentral() 10 | } 11 | 12 | dependencies { 13 | compile ( 14 | // common 15 | 'io.netty:netty-all:4.0.25.Final' 16 | ,'commons-io:commons-io:2.4' 17 | ,'org.apache.commons:commons-lang3:3.3.2' 18 | ,'log4j:log4j:1.2.17' 19 | ,'org.slf4j:slf4j-log4j12:1.7.7' 20 | ,'com.jcraft:jzlib:1.1.3' 21 | ,'org.yaml:snakeyaml:1.14' 22 | 23 | ,'com.google.code.gson:gson:2.3' 24 | ,'com.google.guava:guava:18.0' 25 | ,'com.typesafe.akka:akka-actor_2.11:2.3.6' 26 | ,'io.reactivex:rxjava:1.0.1' 27 | ,'redis.clients:jedis:2.6.1' 28 | 29 | ,'org.apache.avro:avro:1.7.7' 30 | ,'org.apache.avro:avro-ipc:1.7.7' 31 | 32 | 33 | 34 | , fileTree(dir: 'lib', include: '**/*.jar') 35 | ) 36 | testCompile group: 'junit', name: 'junit', version: '4.11' 37 | } -------------------------------------------------------------------------------- /chapter2/data/text-file.txt: -------------------------------------------------------------------------------- 1 | This is a message in text-file.txt -------------------------------------------------------------------------------- /chapter2/lib/netty-codec-ftp-0.2-SNAPSHOT.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trieu/netty-cookbook/6b72058b2dd085a52c7586ced4899490e8ae52df/chapter2/lib/netty-codec-ftp-0.2-SNAPSHOT.jar -------------------------------------------------------------------------------- /chapter2/src/main/avro/mail.avpr: -------------------------------------------------------------------------------- 1 | {"namespace": "avro", 2 | "protocol": "Mail", 3 | 4 | "types": [ 5 | {"name": "Message", "type": "record", 6 | "fields": [ 7 | {"name": "to", "type": "string"}, 8 | {"name": "from", "type": "string"}, 9 | {"name": "body", "type": "string"} 10 | ] 11 | } 12 | ], 13 | 14 | "messages": { 15 | "send": { 16 | "request": [{"name": "message", "type": "Message"}], 17 | "response": "string" 18 | } 19 | } 20 | } -------------------------------------------------------------------------------- /chapter2/src/main/java/avro/Mail.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Autogenerated by Avro 3 | * 4 | * DO NOT EDIT DIRECTLY 5 | */ 6 | package avro; 7 | 8 | @SuppressWarnings("all") 9 | @org.apache.avro.specific.AvroGenerated 10 | public interface Mail { 11 | public static final org.apache.avro.Protocol PROTOCOL = org.apache.avro.Protocol.parse("{\"protocol\":\"Mail\",\"namespace\":\"avro\",\"types\":[{\"type\":\"record\",\"name\":\"Message\",\"fields\":[{\"name\":\"to\",\"type\":\"string\"},{\"name\":\"from\",\"type\":\"string\"},{\"name\":\"body\",\"type\":\"string\"}]}],\"messages\":{\"send\":{\"request\":[{\"name\":\"message\",\"type\":\"Message\"}],\"response\":\"string\"}}}"); 12 | java.lang.CharSequence send(avro.Message message) throws org.apache.avro.AvroRemoteException; 13 | 14 | @SuppressWarnings("all") 15 | public interface Callback extends Mail { 16 | public static final org.apache.avro.Protocol PROTOCOL = avro.Mail.PROTOCOL; 17 | void send(avro.Message message, org.apache.avro.ipc.Callback callback) throws java.io.IOException; 18 | } 19 | } -------------------------------------------------------------------------------- /chapter2/src/main/java/chapter2/recipe10/ClientAvroRPC.java: -------------------------------------------------------------------------------- 1 | package chapter2.recipe10; 2 | 3 | 4 | import java.io.IOException; 5 | import java.net.InetSocketAddress; 6 | 7 | import netty.cookbook.common.LogUtil; 8 | 9 | import org.apache.avro.ipc.NettyTransceiver; 10 | import org.apache.avro.ipc.specific.SpecificRequestor; 11 | import org.apache.avro.util.Utf8; 12 | 13 | import avro.Mail; 14 | import avro.Message; 15 | 16 | /** 17 | * Start ClientAvroRPC, and send a message. 18 | */ 19 | public class ClientAvroRPC { 20 | public static void main(String[] args) throws IOException { 21 | if(args.length < 3){ 22 | args = new String[] {"someone@example.com","myself@example.com","Hello !"}; 23 | } 24 | NettyTransceiver client = new NettyTransceiver(new InetSocketAddress(10000)); 25 | Mail proxy = (Mail) SpecificRequestor.getClient(Mail.class, client); 26 | LogUtil.println("ClientAvroRPC built OK, got proxy, ready to send data ..."); 27 | Message message = new Message(); 28 | message.setTo(new Utf8(args[0])); 29 | message.setFrom(new Utf8(args[1])); 30 | message.setBody(new Utf8(args[2])); 31 | LogUtil.println("Calling proxy.send with message: " + message.toString()); 32 | LogUtil.println("Result from server: " + proxy.send(message)); 33 | client.close(); 34 | } 35 | } -------------------------------------------------------------------------------- /chapter2/src/main/java/chapter2/recipe10/ProxyServerAvroRPC.java: -------------------------------------------------------------------------------- 1 | package chapter2.recipe10; 2 | 3 | import java.io.IOException; 4 | import java.net.InetSocketAddress; 5 | 6 | import netty.cookbook.common.LogUtil; 7 | 8 | import org.apache.avro.ipc.NettyServer; 9 | import org.apache.avro.ipc.Server; 10 | import org.apache.avro.ipc.specific.SpecificResponder; 11 | import org.apache.avro.util.Utf8; 12 | 13 | import avro.Mail; 14 | import avro.Message; 15 | 16 | /** 17 | * @author trieu 18 | * 19 | */ 20 | public class ProxyServerAvroRPC { 21 | public static class MailImpl implements Mail { 22 | public Utf8 send(Message message) { 23 | String s = String.format("message details, to:%s from:%s body:%s", message.getTo(), message.getFrom(), message.getBody()); 24 | LogUtil.println(s); 25 | return new Utf8("Sent OK to "+ message.getTo()); 26 | } 27 | } 28 | private static Server server; 29 | static void startServer() throws IOException { 30 | server = new NettyServer(new SpecificResponder(Mail.class,new MailImpl()), new InetSocketAddress(10000)); 31 | } 32 | public static void main(String[] args) throws Exception { 33 | LogUtil.println("Starting ServerAvroRPC"); 34 | startServer(); 35 | LogUtil.println("ServerAvroRPC started and wait for 15s"); 36 | Thread.sleep(15000); 37 | server.close(); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /chapter2/src/main/java/chapter2/recipe2/Receiver.java: -------------------------------------------------------------------------------- 1 | package chapter2.recipe2; 2 | 3 | import io.netty.channel.ChannelHandlerContext; 4 | import io.netty.channel.ChannelInboundHandlerAdapter; 5 | import io.netty.channel.ChannelInitializer; 6 | import io.netty.channel.ChannelPipeline; 7 | import io.netty.channel.socket.SocketChannel; 8 | import io.netty.handler.codec.string.StringDecoder; 9 | import io.netty.handler.codec.string.StringEncoder; 10 | import netty.cookbook.common.BootstrapTemplate; 11 | 12 | public class Receiver { 13 | static final int PORT = 8007; 14 | static final String HOST = "127.0.0.1"; 15 | public static void main(String[] args) throws Exception { 16 | ChannelInitializer initializer = new ChannelInitializer() { 17 | @Override 18 | public void initChannel(SocketChannel ch) throws Exception { 19 | ChannelPipeline p = ch.pipeline(); 20 | p.addLast(new StringEncoder()); 21 | p.addLast(new StringDecoder()); 22 | p.addLast(new ChannelInboundHandlerAdapter() { 23 | @Override 24 | public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { 25 | System.out.println(msg); 26 | ctx.close(); 27 | } 28 | }); 29 | } 30 | }; 31 | BootstrapTemplate.newServerBootstrap(HOST, PORT, initializer); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /chapter2/src/main/java/chapter2/recipe2/Sender.java: -------------------------------------------------------------------------------- 1 | package chapter2.recipe2; 2 | 3 | import io.netty.channel.ChannelHandlerContext; 4 | import io.netty.channel.ChannelInboundHandlerAdapter; 5 | import io.netty.channel.ChannelInitializer; 6 | import io.netty.channel.ChannelPipeline; 7 | import io.netty.channel.socket.SocketChannel; 8 | import io.netty.handler.codec.string.StringDecoder; 9 | import io.netty.handler.codec.string.StringEncoder; 10 | import netty.cookbook.common.BootstrapTemplate; 11 | 12 | public class Sender { 13 | static final int PORT = 8007; 14 | static final String HOST = "127.0.0.1"; 15 | 16 | public static void main(String[] args) throws InterruptedException { 17 | final String msg = "This is a long message"; 18 | ChannelInitializer initializer = new ChannelInitializer() { 19 | @Override 20 | public void initChannel(SocketChannel ch) throws Exception { 21 | ChannelPipeline p = ch.pipeline(); 22 | p.addLast(new StringEncoder()); 23 | p.addLast(new StringDecoder()); 24 | p.addLast(new ChannelInboundHandlerAdapter() { 25 | @Override 26 | public void channelActive(ChannelHandlerContext ctx) 27 | throws Exception { 28 | //on ready to send 29 | ctx.writeAndFlush(msg); 30 | } 31 | @Override 32 | public void channelRead(ChannelHandlerContext ctx, 33 | Object data) throws Exception { 34 | //on receive 35 | System.out.println("got " + data); 36 | } 37 | }); 38 | } 39 | }; 40 | BootstrapTemplate.newClientBootstrap(HOST, PORT, initializer ); 41 | Thread.sleep(5000); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /chapter2/src/main/java/chapter2/recipe3/PurchaseClient.java: -------------------------------------------------------------------------------- 1 | package chapter2.recipe3; 2 | 3 | import io.netty.channel.ChannelHandler; 4 | import io.netty.channel.ChannelInitializer; 5 | import io.netty.channel.ChannelPipeline; 6 | import io.netty.channel.socket.SocketChannel; 7 | import netty.cookbook.common.BootstrapTemplate; 8 | import netty.cookbook.common.CallbackProcessor; 9 | 10 | public class PurchaseClient { 11 | String host; int port; 12 | public PurchaseClient(String host, int port) { 13 | super(); 14 | this.host = host; 15 | this.port = port; 16 | } 17 | public PurchaseClient send(PurchaseData message, CallbackProcessor asynchCall) throws Exception{ 18 | ChannelHandler clientHandler = new PurchaseClientHandler(message, asynchCall); 19 | ChannelInitializer initializer = new ChannelInitializer() { 20 | @Override 21 | public void initChannel(SocketChannel ch) throws Exception { 22 | ChannelPipeline p = ch.pipeline(); 23 | p.addLast(new PurchaseDataDecoder()); 24 | p.addLast(new PurchaseDataEncoder()); 25 | p.addLast(clientHandler); 26 | } 27 | }; 28 | BootstrapTemplate.newClientBootstrap(host, port, initializer ); 29 | return this; 30 | } 31 | public static void main(String[] args) throws Exception { 32 | int unixTime = (int) (System.currentTimeMillis() / 1000L); 33 | PurchaseData data = new PurchaseData(1001, 499.99f, "Trieu", "Amazon", unixTime, false ); 34 | new PurchaseClient("127.0.0.1",8007).send(data, rs -> { 35 | System.out.println(rs); 36 | }); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /chapter2/src/main/java/chapter2/recipe3/PurchaseData.java: -------------------------------------------------------------------------------- 1 | package chapter2.recipe3; 2 | 3 | import java.io.Serializable; 4 | 5 | import com.google.gson.Gson; 6 | 7 | public class PurchaseData implements Serializable{ 8 | private static final long serialVersionUID = -5467453661148034694L; 9 | private final int itemId; 10 | private final float price; 11 | private final String buyer; 12 | private final String seller; 13 | private final int unixTime; 14 | private final boolean processed; 15 | public PurchaseData(int itemId, float price, String buyer, String seller, 16 | int unixTime, boolean processed) { 17 | super(); 18 | this.itemId = itemId; 19 | this.price = price; 20 | this.buyer = buyer; 21 | this.seller = seller; 22 | this.unixTime = unixTime; 23 | this.processed = processed; 24 | } 25 | public PurchaseData(Object obj, boolean processed) { 26 | super(); 27 | PurchaseData data = (PurchaseData)obj; 28 | this.itemId = data.itemId; 29 | this.price = data.price; 30 | this.buyer = data.buyer; 31 | this.seller = data.seller; 32 | this.unixTime = data.unixTime; 33 | this.processed = processed; 34 | } 35 | public float getPrice() { 36 | return price; 37 | } 38 | public String getBuyer() { 39 | return buyer; 40 | } 41 | public String getSeller() { 42 | return seller; 43 | } 44 | public int getUnixTime() { 45 | return unixTime; 46 | } 47 | public int getItemId() { 48 | return itemId; 49 | } 50 | public boolean isProcessed() { 51 | return processed; 52 | } 53 | @Override 54 | public String toString() { 55 | return new Gson().toJson(this); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /chapter2/src/main/java/chapter2/recipe3/PurchaseDataDecoder.java: -------------------------------------------------------------------------------- 1 | package chapter2.recipe3; 2 | 3 | import chapter2.recipe6.NettyMonitorIO; 4 | import io.netty.buffer.ByteBuf; 5 | import io.netty.channel.ChannelHandlerContext; 6 | import io.netty.handler.codec.serialization.ClassResolvers; 7 | import io.netty.handler.codec.serialization.ObjectDecoder; 8 | 9 | public class PurchaseDataDecoder extends ObjectDecoder { 10 | public PurchaseDataDecoder() { 11 | super(ClassResolvers.weakCachingConcurrentResolver(null)); 12 | } 13 | @Override 14 | protected Object decode(ChannelHandlerContext ctx, ByteBuf buf) 15 | throws Exception { 16 | Object object = super.decode(ctx, buf); 17 | NettyMonitorIO.updateDataIn(buf); 18 | return object; 19 | } 20 | } -------------------------------------------------------------------------------- /chapter2/src/main/java/chapter2/recipe3/PurchaseDataEncoder.java: -------------------------------------------------------------------------------- 1 | package chapter2.recipe3; 2 | 3 | import io.netty.buffer.ByteBuf; 4 | import io.netty.channel.ChannelHandlerContext; 5 | import io.netty.handler.codec.serialization.ObjectEncoder; 6 | 7 | import java.io.Serializable; 8 | 9 | import chapter2.recipe6.NettyMonitorIO; 10 | 11 | public class PurchaseDataEncoder extends ObjectEncoder { 12 | @Override 13 | protected void encode(ChannelHandlerContext ctx, Serializable msg, ByteBuf buf) throws Exception { 14 | super.encode(ctx, msg, buf); 15 | NettyMonitorIO.updateDataOut(buf); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /chapter2/src/main/java/chapter2/recipe3/PurchaseServer.java: -------------------------------------------------------------------------------- 1 | package chapter2.recipe3; 2 | 3 | import io.netty.channel.ChannelHandlerContext; 4 | import io.netty.channel.ChannelInboundHandlerAdapter; 5 | import io.netty.channel.ChannelInitializer; 6 | import io.netty.channel.ChannelPipeline; 7 | import io.netty.channel.socket.SocketChannel; 8 | import netty.cookbook.common.BootstrapTemplate; 9 | 10 | import org.apache.log4j.Logger; 11 | 12 | public class PurchaseServer { 13 | final static Logger logger = Logger.getLogger(PurchaseServer.class); 14 | 15 | static final int PORT = 8007; 16 | static final String HOST = "127.0.0.1"; 17 | 18 | public static void main(String[] args) throws Exception { 19 | ChannelInitializer initializer = new ChannelInitializer() { 20 | @Override 21 | public void initChannel(SocketChannel ch) throws Exception { 22 | ChannelPipeline p = ch.pipeline(); 23 | p.addLast(new PurchaseDataDecoder()); 24 | p.addLast(new PurchaseDataEncoder()); 25 | p.addLast(new ChannelInboundHandlerAdapter() { 26 | @Override 27 | public void channelRead(ChannelHandlerContext ctx, 28 | Object data) throws Exception { 29 | System.out.println("processed Purchase " + data); 30 | PurchaseData processed = new PurchaseData(data, true); 31 | ctx.writeAndFlush(processed); 32 | } 33 | }); 34 | } 35 | }; 36 | BootstrapTemplate.newServerBootstrap(HOST, PORT, initializer); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /chapter2/src/main/java/chapter2/recipe6/NettyMonitorIO.java: -------------------------------------------------------------------------------- 1 | package chapter2.recipe6; 2 | 3 | import io.netty.buffer.ByteBuf; 4 | 5 | import java.text.DateFormat; 6 | import java.text.SimpleDateFormat; 7 | import java.util.Date; 8 | import java.util.Timer; 9 | import java.util.TimerTask; 10 | import java.util.concurrent.ConcurrentHashMap; 11 | import java.util.concurrent.ConcurrentMap; 12 | 13 | /** 14 | * @author trieunt 15 | * 16 | */ 17 | public class NettyMonitorIO { 18 | static final DateFormat DATE_TIME_FORMAT = new SimpleDateFormat("yyyy-MM-dd HH:mm"); 19 | static ConcurrentMap dataOutStats = new ConcurrentHashMap(); 20 | static ConcurrentMap dataInStats = new ConcurrentHashMap(); 21 | public static long updateDataOut(ByteBuf buf) { 22 | String time = DATE_TIME_FORMAT.format(new Date()); 23 | long c = dataOutStats.getOrDefault(time, 0L) + buf.readableBytes(); 24 | dataOutStats.put(time, c); 25 | return c; 26 | } 27 | public static long updateDataIn(ByteBuf buf) { 28 | String time = DATE_TIME_FORMAT.format(new Date()); 29 | long c = dataInStats.getOrDefault(time, 0L) + buf.writableBytes(); 30 | dataInStats.put(time, c); 31 | return c; 32 | } 33 | static { 34 | new Timer(true).schedule(new TimerTask() { 35 | @Override 36 | public void run() { 37 | System.out.println("--------------------------------"); 38 | System.out.println("Data In Stats:"); 39 | dataInStats.forEach((String key, Long val)->{ 40 | System.out.println(key + " : "+val); 41 | }); 42 | System.out.println("Data Out Stats:"); 43 | dataOutStats.forEach((String key, Long val)->{ 44 | System.out.println(key + " : "+val); 45 | }); 46 | } 47 | }, 2000, 2000); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /chapter2/src/main/java/chapter2/recipe7/HeartBeatHandler.java: -------------------------------------------------------------------------------- 1 | package chapter2.recipe7; 2 | 3 | import io.netty.buffer.ByteBuf; 4 | import io.netty.buffer.Unpooled; 5 | import io.netty.channel.ChannelHandlerContext; 6 | import io.netty.channel.SimpleChannelInboundHandler; 7 | import io.netty.channel.socket.DatagramPacket; 8 | import io.netty.util.CharsetUtil; 9 | 10 | import java.util.Date; 11 | import java.util.LinkedList; 12 | import java.util.Queue; 13 | import java.util.Timer; 14 | import java.util.TimerTask; 15 | 16 | public class HeartBeatHandler extends 17 | SimpleChannelInboundHandler { 18 | private static final Queue logQueue = new LinkedList(); 19 | static String log(String log) { 20 | return String.valueOf(logQueue.add(log)); 21 | } 22 | static { 23 | new Timer(true).schedule(new TimerTask() { 24 | @Override 25 | public void run() { 26 | while ( ! logQueue.isEmpty() ) { 27 | // log to Kafka or somewhere 28 | String s = logQueue.poll(); 29 | if(s != null){ 30 | System.out.println(s); 31 | } 32 | } 33 | } 34 | }, 1000, 2000); 35 | } 36 | 37 | @Override 38 | public void channelReadComplete(ChannelHandlerContext ctx) { 39 | ctx.flush(); 40 | } 41 | 42 | @Override 43 | public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { 44 | cause.printStackTrace(); 45 | // We don't close the channel because we can keep serving requests. 46 | } 47 | 48 | @Override 49 | protected void channelRead0(ChannelHandlerContext ctx, DatagramPacket packet) throws Exception { 50 | System.err.println(packet); 51 | String s = packet.content().toString(CharsetUtil.UTF_8); 52 | System.out.println(s); 53 | ByteBuf buf = Unpooled.copiedBuffer("I'm alive at "+new Date(), CharsetUtil.UTF_8); 54 | ctx.write(new DatagramPacket(buf, packet.sender())); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /chapter2/src/main/java/chapter2/recipe7/ImportantServer.java: -------------------------------------------------------------------------------- 1 | package chapter2.recipe7; 2 | 3 | import io.netty.channel.EventLoopGroup; 4 | import io.netty.channel.nio.NioEventLoopGroup; 5 | import netty.cookbook.common.BootstrapTemplate; 6 | 7 | /** 8 | * @author trieu 9 | * 10 | * demo for HeartBeat monitor 11 | * 12 | */ 13 | public class ImportantServer { 14 | private static final int PORT = 8080; 15 | public static void main(String[] args) throws Exception { 16 | EventLoopGroup loopGroup = new NioEventLoopGroup(); 17 | try { 18 | BootstrapTemplate.newBootstrapUDP(loopGroup, new HeartBeatHandler(), PORT) 19 | .sync().channel().closeFuture().await(); 20 | } finally { 21 | loopGroup.shutdownGracefully(); 22 | } 23 | } 24 | } -------------------------------------------------------------------------------- /chapter2/src/main/java/chapter2/recipe8/SimpleSctpClient.java: -------------------------------------------------------------------------------- 1 | package chapter2.recipe8; 2 | 3 | import io.netty.bootstrap.Bootstrap; 4 | import io.netty.channel.ChannelFuture; 5 | import io.netty.channel.ChannelInitializer; 6 | import io.netty.channel.ChannelPipeline; 7 | import io.netty.channel.EventLoopGroup; 8 | import io.netty.channel.nio.NioEventLoopGroup; 9 | import io.netty.channel.sctp.SctpChannel; 10 | import io.netty.channel.sctp.SctpChannelOption; 11 | import io.netty.channel.sctp.nio.NioSctpChannel; 12 | 13 | 14 | public final class SimpleSctpClient { 15 | 16 | static final String HOST = System.getProperty("host", "127.0.0.1"); 17 | static final int PORT = Integer.parseInt(System.getProperty("port", "8007")); 18 | 19 | public static void main(String[] args) throws Exception { 20 | EventLoopGroup loopGroup = new NioEventLoopGroup(); 21 | try { 22 | ChannelFuture f = new Bootstrap().group(loopGroup) 23 | .channel(NioSctpChannel.class) 24 | // set SCTP option 25 | .option(SctpChannelOption.SCTP_NODELAY, true) 26 | .handler(new ChannelInitializer() { 27 | @Override 28 | public void initChannel(SctpChannel ch) throws Exception { 29 | ChannelPipeline p = ch.pipeline(); 30 | p.addLast(new SimpleSctpClientHandler()); 31 | } 32 | }).connect(HOST, PORT).sync(); 33 | f.channel().closeFuture().sync(); 34 | } finally { 35 | loopGroup.shutdownGracefully(); 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /chapter2/src/main/java/chapter2/recipe8/SimpleSctpClientHandler.java: -------------------------------------------------------------------------------- 1 | package chapter2.recipe8; 2 | 3 | import io.netty.buffer.ByteBuf; 4 | import io.netty.buffer.Unpooled; 5 | import io.netty.channel.ChannelHandlerContext; 6 | import io.netty.channel.ChannelInboundHandlerAdapter; 7 | import io.netty.channel.sctp.SctpMessage; 8 | import io.netty.util.CharsetUtil; 9 | 10 | 11 | public class SimpleSctpClientHandler extends ChannelInboundHandlerAdapter { 12 | private final ByteBuf firstMessage, secondMessage; 13 | public SimpleSctpClientHandler() { 14 | firstMessage = Unpooled.copiedBuffer("first message",CharsetUtil.UTF_8); 15 | secondMessage = Unpooled.copiedBuffer("second message",CharsetUtil.UTF_8); 16 | } 17 | @Override 18 | public void channelActive(ChannelHandlerContext ctx) { 19 | ctx.write(new SctpMessage(0, 0, firstMessage)); 20 | ctx.write(new SctpMessage(0, 0, secondMessage)); 21 | ctx.flush(); 22 | } 23 | 24 | @Override 25 | public void channelRead(ChannelHandlerContext ctx, Object msg) { 26 | System.out.println(msg); 27 | } 28 | 29 | @Override 30 | public void channelReadComplete(ChannelHandlerContext ctx) { 31 | ctx.flush(); 32 | } 33 | 34 | @Override 35 | public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { 36 | // Close the connection when an exception is raised. 37 | cause.printStackTrace(); 38 | ctx.close(); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /chapter2/src/main/java/chapter2/recipe8/SimpleSctpServer.java: -------------------------------------------------------------------------------- 1 | package chapter2.recipe8; 2 | 3 | import io.netty.bootstrap.ServerBootstrap; 4 | import io.netty.channel.ChannelFuture; 5 | import io.netty.channel.ChannelInitializer; 6 | import io.netty.channel.ChannelOption; 7 | import io.netty.channel.ChannelPipeline; 8 | import io.netty.channel.EventLoopGroup; 9 | import io.netty.channel.nio.NioEventLoopGroup; 10 | import io.netty.channel.sctp.SctpChannel; 11 | import io.netty.channel.sctp.nio.NioSctpServerChannel; 12 | import io.netty.handler.logging.LogLevel; 13 | import io.netty.handler.logging.LoggingHandler; 14 | 15 | 16 | public final class SimpleSctpServer { 17 | 18 | static final int PORT = Integer.parseInt(System.getProperty("port", "8007")); 19 | 20 | public static void main(String[] args) throws Exception { 21 | EventLoopGroup mainLoop = new NioEventLoopGroup(1); 22 | EventLoopGroup workerLoop = new NioEventLoopGroup(); 23 | try { 24 | ChannelFuture f = new ServerBootstrap().group(mainLoop, workerLoop) 25 | .channel(NioSctpServerChannel.class) 26 | .option(ChannelOption.SO_BACKLOG, 100) 27 | .handler(new LoggingHandler(LogLevel.INFO)) 28 | .childHandler(new ChannelInitializer() { 29 | @Override 30 | public void initChannel(SctpChannel ch) throws Exception { 31 | ChannelPipeline p = ch.pipeline(); 32 | p.addLast(new SimpleSctpServerHandler()); 33 | } 34 | }).bind(PORT).sync(); 35 | f.channel().closeFuture().sync(); 36 | } finally { 37 | mainLoop.shutdownGracefully(); 38 | workerLoop.shutdownGracefully(); 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /chapter2/src/main/java/chapter2/recipe8/SimpleSctpServerHandler.java: -------------------------------------------------------------------------------- 1 | package chapter2.recipe8; 2 | 3 | import io.netty.channel.ChannelHandler.Sharable; 4 | import io.netty.channel.ChannelHandlerContext; 5 | import io.netty.channel.ChannelInboundHandlerAdapter; 6 | import io.netty.channel.sctp.SctpMessage; 7 | import io.netty.util.CharsetUtil; 8 | 9 | /** 10 | * Handler implementation for the SCTP echo server. 11 | */ 12 | @Sharable 13 | public class SimpleSctpServerHandler extends ChannelInboundHandlerAdapter { 14 | @Override 15 | public void channelRead(ChannelHandlerContext ctx, Object msg) { 16 | System.out.println(msg); 17 | if(msg instanceof SctpMessage){ 18 | SctpMessage sctpMsg = (SctpMessage) msg; 19 | System.out.println(sctpMsg.content().toString(CharsetUtil.UTF_8)); 20 | ctx.write(sctpMsg); 21 | } 22 | } 23 | 24 | @Override 25 | public void channelReadComplete(ChannelHandlerContext ctx) { 26 | ctx.flush(); 27 | } 28 | 29 | @Override 30 | public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { 31 | // Close the connection when an exception is raised. 32 | cause.printStackTrace(); 33 | ctx.close(); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /chapter2/src/main/java/chapter2/recipe9/FileReceiver.java: -------------------------------------------------------------------------------- 1 | package chapter2.recipe9; 2 | 3 | import java.io.File; 4 | import java.io.IOException; 5 | import java.io.InputStream; 6 | import java.nio.file.Files; 7 | 8 | import com.butor.netty.handler.codec.ftp.DataReceiver; 9 | 10 | class FileReceiver implements DataReceiver { 11 | @Override 12 | public void receive(String name, InputStream data) throws IOException { 13 | System.out.println("got file: [" + name + "]"); 14 | //copy to local folder 15 | Files.copy(data, new File("./data/"+name).toPath()); 16 | } 17 | } -------------------------------------------------------------------------------- /chapter2/src/main/java/chapter2/recipe9/SimpleServerFTP.java: -------------------------------------------------------------------------------- 1 | package chapter2.recipe9; 2 | 3 | import io.netty.channel.ChannelInitializer; 4 | import io.netty.channel.ChannelPipeline; 5 | import io.netty.channel.socket.SocketChannel; 6 | import netty.cookbook.common.BootstrapTemplate; 7 | 8 | import com.butor.netty.handler.codec.ftp.CrlfStringDecoder; 9 | import com.butor.netty.handler.codec.ftp.DataReceiver; 10 | import com.butor.netty.handler.codec.ftp.FtpServerHandler; 11 | import com.butor.netty.handler.codec.ftp.cmd.DefaultCommandExecutionTemplate; 12 | 13 | public class SimpleServerFTP { 14 | public static void main(String... args) throws Exception { 15 | DataReceiver dataReceiver = new FileReceiver(); 16 | final DefaultCommandExecutionTemplate tpl = new DefaultCommandExecutionTemplate(dataReceiver); 17 | ChannelInitializer initializer = new ChannelInitializer() { 18 | @Override 19 | protected void initChannel(SocketChannel ch) throws Exception { 20 | ChannelPipeline p = ch.pipeline(); 21 | p.addLast(new CrlfStringDecoder()); 22 | p.addLast(new FtpServerHandler(tpl)); 23 | } 24 | }; 25 | BootstrapTemplate.newServerBootstrap("127.0.0.1", 2121, initializer); 26 | } 27 | } -------------------------------------------------------------------------------- /chapter2/src/main/java/log4j.properties: -------------------------------------------------------------------------------- 1 | # Root logger option 2 | log4j.rootLogger=INFO, stdout 3 | 4 | # Redirect log messages to console 5 | log4j.appender.stdout=org.apache.log4j.ConsoleAppender 6 | log4j.appender.stdout.Target=System.out 7 | log4j.appender.stdout.layout=org.apache.log4j.PatternLayout 8 | log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n 9 | 10 | # Redirect log messages to a log file, support file rolling. 11 | log4j.appender.file=org.apache.log4j.RollingFileAppender 12 | log4j.appender.file.File=./log/java-cookbook-demo 13 | log4j.appender.file.MaxFileSize=5MB 14 | log4j.appender.file.MaxBackupIndex=10 15 | log4j.appender.file.layout=org.apache.log4j.PatternLayout 16 | log4j.appender.file.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n -------------------------------------------------------------------------------- /chapter2/src/main/java/netty/cookbook/common/CallbackProcessor.java: -------------------------------------------------------------------------------- 1 | package netty.cookbook.common; 2 | 3 | @FunctionalInterface 4 | public interface CallbackProcessor { 5 | public void process(Object obj); 6 | } -------------------------------------------------------------------------------- /chapter2/src/main/java/netty/cookbook/common/CharPool.java: -------------------------------------------------------------------------------- 1 | package netty.cookbook.common; 2 | 3 | public class CharPool { 4 | 5 | public static final char AMPERSAND = '&'; 6 | 7 | public static final char APOSTROPHE = '\''; 8 | 9 | public static final char AT = '@'; 10 | 11 | public static final char BACK_SLASH = '\\'; 12 | 13 | public static final char CLOSE_BRACKET = ']'; 14 | 15 | public static final char CLOSE_CURLY_BRACE = '}'; 16 | 17 | public static final char CLOSE_PARENTHESIS = ')'; 18 | 19 | public static final char COLON = ':'; 20 | 21 | public static final char COMMA = ','; 22 | 23 | public static final char DASH = '-'; 24 | 25 | public static final char EQUAL = '='; 26 | 27 | public static final char GREATER_THAN = '>'; 28 | 29 | public static final char FORWARD_SLASH = '/'; 30 | 31 | public static final char LESS_THAN = '<'; 32 | 33 | public static final char LOWER_CASE_E = 'e'; 34 | 35 | public static final char MINUS = '-'; 36 | 37 | public static final char NEW_LINE = '\n'; 38 | 39 | public static final char OPEN_BRACKET = '['; 40 | 41 | public static final char OPEN_CURLY_BRACE = '{'; 42 | 43 | public static final char OPEN_PARENTHESIS = '('; 44 | 45 | public static final char PERCENT = '%'; 46 | 47 | public static final char PERIOD = '.'; 48 | 49 | public static final char PIPE = '|'; 50 | 51 | public static final char PLUS = '+'; 52 | 53 | public static final char POUND = '#'; 54 | 55 | public static final char QUESTION = '?'; 56 | 57 | public static final char QUOTE = '\"'; 58 | 59 | public static final char RETURN = '\r'; 60 | 61 | public static final char SEMICOLON = ';'; 62 | 63 | public static final char SLASH = FORWARD_SLASH; 64 | 65 | public static final char SPACE = ' '; 66 | 67 | public static final char STAR = '*'; 68 | 69 | public static final char TILDE = '~'; 70 | 71 | public static final char UNDERLINE = '_'; 72 | 73 | public static final char UPPER_CASE_E = 'E'; 74 | 75 | public static final char TAB = '\t'; 76 | 77 | } 78 | -------------------------------------------------------------------------------- /chapter2/src/main/java/netty/cookbook/common/LogUtil.java: -------------------------------------------------------------------------------- 1 | package netty.cookbook.common; 2 | 3 | public class LogUtil { 4 | 5 | public static void println(Object obj){ 6 | System.out.println(obj); 7 | } 8 | 9 | public static void println(String obj){ 10 | System.out.println(obj); 11 | } 12 | 13 | 14 | } 15 | -------------------------------------------------------------------------------- /chapter2/src/main/java/netty/cookbook/common/TcpChannelHandler.java: -------------------------------------------------------------------------------- 1 | package netty.cookbook.common; 2 | 3 | import io.netty.channel.ChannelHandlerContext; 4 | 5 | @FunctionalInterface 6 | public interface TcpChannelHandler { 7 | public void process(ChannelHandlerContext ctx, Object msg); 8 | } 9 | -------------------------------------------------------------------------------- /chapter2/src/main/java/netty/cookbook/common/UrlUtil.java: -------------------------------------------------------------------------------- 1 | package netty.cookbook.common; 2 | 3 | import java.net.MalformedURLException; 4 | import java.net.URL; 5 | 6 | public class UrlUtil { 7 | public final static String REGEX_FOR_ROOT_DOMAIN = ".*\\.(?=.*\\.)"; 8 | 9 | public static String getRootDomain(String fullUrl) throws MalformedURLException{ 10 | return new URL(fullUrl).getHost().replaceAll(REGEX_FOR_ROOT_DOMAIN, ""); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /chapter2/tools/avro-tools-1.7.7.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trieu/netty-cookbook/6b72058b2dd085a52c7586ced4899490e8ae52df/chapter2/tools/avro-tools-1.7.7.jar -------------------------------------------------------------------------------- /chapter3/.gitignore: -------------------------------------------------------------------------------- 1 | /bin/ 2 | /build/ 3 | -------------------------------------------------------------------------------- /chapter3/.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | chapter3 4 | 5 | 6 | 7 | 8 | 9 | org.eclipse.jdt.core.javabuilder 10 | 11 | 12 | 13 | 14 | 15 | org.springsource.ide.eclipse.gradle.core.nature 16 | org.eclipse.jdt.core.javanature 17 | 18 | 19 | -------------------------------------------------------------------------------- /chapter3/README.md: -------------------------------------------------------------------------------- 1 | Netty Cookbook - chapter 3 code -------------------------------------------------------------------------------- /chapter3/configs/redis-connection-pool-configs.json: -------------------------------------------------------------------------------- 1 | { 2 | maxTotal : 3000, 3 | maxIdle : 20, 4 | minIdle : 2, 5 | maxWaitMillis : 5000; 6 | numTestsPerEvictionRun : 10, 7 | testOnBorrow : true, 8 | testOnReturn : true, 9 | testWhileIdle : true, 10 | timeBetweenEvictionRunsMillis : 60000 11 | } -------------------------------------------------------------------------------- /chapter3/lib/DateAdapterJ-1.1.3-20141216.175259-8.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trieu/netty-cookbook/6b72058b2dd085a52c7586ced4899490e8ae52df/chapter3/lib/DateAdapterJ-1.1.3-20141216.175259-8.jar -------------------------------------------------------------------------------- /chapter3/lib/RestExpress-0.11.0-20150113.201733-1.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trieu/netty-cookbook/6b72058b2dd085a52c7586ced4899490e8ae52df/chapter3/lib/RestExpress-0.11.0-20150113.201733-1.jar -------------------------------------------------------------------------------- /chapter3/lib/RestExpress-Common-0.11.0-20150113.201714-1.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trieu/netty-cookbook/6b72058b2dd085a52c7586ced4899490e8ae52df/chapter3/lib/RestExpress-Common-0.11.0-20150113.201714-1.jar -------------------------------------------------------------------------------- /chapter3/lib/alpn-boot-8.1.0.v20141016.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trieu/netty-cookbook/6b72058b2dd085a52c7586ced4899490e8ae52df/chapter3/lib/alpn-boot-8.1.0.v20141016.jar -------------------------------------------------------------------------------- /chapter3/src/main/java/chapter3/recipe1/UriMatcher.java: -------------------------------------------------------------------------------- 1 | package chapter3.recipe1; 2 | 3 | public interface UriMatcher { 4 | public boolean match(String uri); 5 | } 6 | -------------------------------------------------------------------------------- /chapter3/src/main/java/chapter3/recipe2/HttpServerSpringMVC.java: -------------------------------------------------------------------------------- 1 | package chapter3.recipe2; 2 | 3 | import io.netty.bootstrap.ServerBootstrap; 4 | import io.netty.channel.nio.NioEventLoopGroup; 5 | import io.netty.channel.socket.nio.NioServerSocketChannel; 6 | 7 | public class HttpServerSpringMVC { 8 | private final String host; 9 | private final int port; 10 | 11 | public HttpServerSpringMVC(String host,int port) { 12 | this.host = host; 13 | this.port = port; 14 | } 15 | 16 | public void run() throws Exception { 17 | ServerBootstrap server = new ServerBootstrap(); 18 | NioEventLoopGroup pGroup = new NioEventLoopGroup(); 19 | NioEventLoopGroup cGroup = new NioEventLoopGroup(); 20 | try { 21 | server.group(pGroup, cGroup) 22 | .channel(NioServerSocketChannel.class) 23 | .childHandler(new DispatcherServletChannelInitializer(WebConfig.class)); 24 | server.bind(host, port).sync().channel().closeFuture().sync(); 25 | } 26 | finally { 27 | cGroup.shutdownGracefully(); 28 | pGroup.shutdownGracefully(); 29 | } 30 | } 31 | 32 | public static void main(String[] args) throws Exception { 33 | String host; 34 | int port; 35 | if (args.length > 0) { 36 | host = args[0]; 37 | port = Integer.parseInt(args[1]); 38 | } else { 39 | host = "127.0.0.1"; 40 | port = 8080; 41 | } 42 | new HttpServerSpringMVC(host, port).run(); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /chapter3/src/main/java/chapter3/recipe2/TemplateConfiguration.java: -------------------------------------------------------------------------------- 1 | package chapter3.recipe2; 2 | 3 | import org.springframework.context.annotation.Bean; 4 | import org.springframework.context.annotation.Configuration; 5 | import org.springframework.web.servlet.ViewResolver; 6 | import org.thymeleaf.spring4.SpringTemplateEngine; 7 | import org.thymeleaf.spring4.view.ThymeleafViewResolver; 8 | import org.thymeleaf.templateresolver.ClassLoaderTemplateResolver; 9 | 10 | @Configuration 11 | public class TemplateConfiguration { 12 | private static final String HTML_EXT = ".html"; 13 | private static final String TEMPLATE_FOLDER = "templates/"; 14 | private static final String XHTML = "XHTML"; 15 | 16 | @Bean 17 | public ViewResolver viewResolver() { 18 | ClassLoaderTemplateResolver templateResolver = new ClassLoaderTemplateResolver(); 19 | templateResolver.setTemplateMode(XHTML); 20 | templateResolver.setPrefix(TEMPLATE_FOLDER); 21 | templateResolver.setSuffix(HTML_EXT); 22 | SpringTemplateEngine engine = new SpringTemplateEngine(); 23 | engine.setTemplateResolver(templateResolver); 24 | ThymeleafViewResolver viewResolver = new ThymeleafViewResolver(); 25 | viewResolver.setTemplateEngine(engine); 26 | return viewResolver; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /chapter3/src/main/java/chapter3/recipe2/WebConfig.java: -------------------------------------------------------------------------------- 1 | package chapter3.recipe2; 2 | 3 | import org.springframework.context.annotation.ComponentScan; 4 | import org.springframework.context.annotation.Configuration; 5 | import org.springframework.web.servlet.config.annotation.EnableWebMvc; 6 | import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; 7 | 8 | 9 | @Configuration 10 | @EnableWebMvc 11 | @ComponentScan(basePackages=WebConfig.BASE_PACKAGE_NAME) 12 | public class WebConfig extends WebMvcConfigurerAdapter { 13 | static final String BASE_PACKAGE_NAME = "chapter3.recipe2"; 14 | } 15 | -------------------------------------------------------------------------------- /chapter3/src/main/java/chapter3/recipe3/HttpFileServer.java: -------------------------------------------------------------------------------- 1 | package chapter3.recipe3; 2 | 3 | import netty.cookbook.common.NettyServerUtil; 4 | 5 | public class HttpFileServer { 6 | 7 | public static void main(String[] args) throws Exception { 8 | int port = 8080; 9 | String ip = "127.0.01"; 10 | NettyServerUtil.newHttpServerBootstrap(ip, port, new HttpStaticFileServerHandler() ); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /chapter3/src/main/java/chapter3/recipe4/NettyHttpServerWithCORS.java: -------------------------------------------------------------------------------- 1 | package chapter3.recipe4; 2 | 3 | import static io.netty.handler.codec.http.HttpMethod.DELETE; 4 | import static io.netty.handler.codec.http.HttpMethod.GET; 5 | import static io.netty.handler.codec.http.HttpMethod.POST; 6 | import static io.netty.handler.codec.http.HttpMethod.PUT; 7 | import io.netty.channel.ChannelInitializer; 8 | import io.netty.channel.ChannelPipeline; 9 | import io.netty.channel.socket.SocketChannel; 10 | import io.netty.handler.codec.http.HttpObjectAggregator; 11 | import io.netty.handler.codec.http.HttpRequestDecoder; 12 | import io.netty.handler.codec.http.HttpResponseEncoder; 13 | import io.netty.handler.codec.http.cors.CorsConfig; 14 | import io.netty.handler.codec.http.cors.CorsHandler; 15 | import io.netty.handler.stream.ChunkedWriteHandler; 16 | import netty.cookbook.common.NettyServerUtil; 17 | 18 | public class NettyHttpServerWithCORS { 19 | 20 | public static void main(String[] args) { 21 | String ip = "127.0.0.1"; 22 | int port = 8080; 23 | ChannelInitializer channelInit = new ChannelInitializer() { 24 | @Override 25 | protected void initChannel(SocketChannel ch) throws Exception { 26 | ChannelPipeline p = ch.pipeline(); 27 | 28 | CorsConfig corsConfig = CorsConfig.withAnyOrigin() 29 | .allowedRequestHeaders("content-type","accept","MyCustomHeader") 30 | .allowedRequestMethods(PUT,POST,GET,DELETE) 31 | .build(); 32 | 33 | p.addLast(new HttpResponseEncoder()); 34 | p.addLast(new HttpRequestDecoder()); 35 | p.addLast(new HttpObjectAggregator(65536)); 36 | p.addLast(new ChunkedWriteHandler()); 37 | p.addLast(new CorsHandler(corsConfig)); 38 | p.addLast(new SimpleCORSHandler()); 39 | } 40 | }; 41 | NettyServerUtil.newHttpServerBootstrap(ip, port, channelInit); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /chapter3/src/main/java/chapter3/recipe5/HttpServerSPDY.java: -------------------------------------------------------------------------------- 1 | package chapter3.recipe5; 2 | 3 | import io.netty.channel.ChannelInitializer; 4 | import io.netty.channel.ChannelPipeline; 5 | import io.netty.channel.socket.SocketChannel; 6 | import io.netty.handler.codec.spdy.SpdyOrHttpChooser.SelectedProtocol; 7 | import io.netty.handler.ssl.ApplicationProtocolConfig; 8 | import io.netty.handler.ssl.ApplicationProtocolConfig.Protocol; 9 | import io.netty.handler.ssl.ApplicationProtocolConfig.SelectedListenerFailureBehavior; 10 | import io.netty.handler.ssl.ApplicationProtocolConfig.SelectorFailureBehavior; 11 | import io.netty.handler.ssl.IdentityCipherSuiteFilter; 12 | import io.netty.handler.ssl.SslContext; 13 | import io.netty.handler.ssl.util.SelfSignedCertificate; 14 | import netty.cookbook.common.NettyServerUtil; 15 | 16 | public class HttpServerSPDY { 17 | 18 | //http://www.chromium.org/spdy 19 | 20 | public static void main(String[] args) throws Exception { 21 | String ip = "127.0.0.1"; 22 | int port = 8080; 23 | // Configure SSL. 24 | SelfSignedCertificate ssc = new SelfSignedCertificate(); 25 | final SslContext sslCtx = SslContext.newServerContext( 26 | ssc.certificate(), ssc.privateKey(), null, null, 27 | IdentityCipherSuiteFilter.INSTANCE, 28 | new ApplicationProtocolConfig(Protocol.ALPN, 29 | SelectorFailureBehavior.FATAL_ALERT, 30 | SelectedListenerFailureBehavior.FATAL_ALERT, 31 | SelectedProtocol.SPDY_3_1.protocolName(), 32 | SelectedProtocol.HTTP_1_1.protocolName()), 0, 0); 33 | 34 | ChannelInitializer channelInit = new ChannelInitializer() { 35 | @Override 36 | protected void initChannel(SocketChannel ch) throws Exception { 37 | ChannelPipeline p = ch.pipeline(); 38 | p.addLast(sslCtx.newHandler(ch.alloc())); 39 | p.addLast(new SpdyOrHttpHandler()); 40 | } 41 | }; 42 | NettyServerUtil.newHttpServerBootstrap(ip, port, channelInit); 43 | } 44 | 45 | } 46 | -------------------------------------------------------------------------------- /chapter3/src/main/java/chapter3/recipe5/SpdyOrHttpHandler.java: -------------------------------------------------------------------------------- 1 | package chapter3.recipe5; 2 | 3 | import io.netty.channel.ChannelInboundHandler; 4 | import io.netty.handler.codec.spdy.SpdyOrHttpChooser; 5 | 6 | public class SpdyOrHttpHandler extends SpdyOrHttpChooser { 7 | private static final int MAX_CONTENT_LENGTH = 1024 * 100; 8 | public SpdyOrHttpHandler() { 9 | this(MAX_CONTENT_LENGTH, MAX_CONTENT_LENGTH); 10 | } 11 | public SpdyOrHttpHandler(int maxSpdyContentLength, int maxHttpContentLength) { 12 | super(maxSpdyContentLength, maxHttpContentLength); 13 | } 14 | @Override 15 | protected ChannelInboundHandler createHttpRequestHandlerForHttp() { 16 | return new SpdyServerHandler(); 17 | } 18 | } -------------------------------------------------------------------------------- /chapter3/src/main/java/chapter3/recipe6/SimpleHttpRequest.java: -------------------------------------------------------------------------------- 1 | package chapter3.recipe6; 2 | 3 | import io.netty.handler.codec.http.Cookie; 4 | import io.netty.handler.codec.http.HttpHeaders; 5 | 6 | import java.util.List; 7 | import java.util.Map; 8 | import java.util.Set; 9 | 10 | import com.google.gson.Gson; 11 | 12 | public class SimpleHttpRequest { 13 | protected String uri = ""; 14 | protected boolean notAuthorized; 15 | protected Set cookies; 16 | protected Map> parameters; 17 | protected HttpHeaders headers; 18 | protected byte[] body; 19 | 20 | public SimpleHttpRequest() { 21 | // TODO Auto-generated constructor stub 22 | } 23 | 24 | public SimpleHttpRequest(String uri) { 25 | super(); 26 | this.uri = uri; 27 | } 28 | 29 | public SimpleHttpRequest(String uri, Map> parameters) { 30 | super(); 31 | this.uri = uri; 32 | this.parameters = parameters; 33 | } 34 | 35 | public String getUri() { 36 | return uri; 37 | } 38 | 39 | public void setUri(String uri) { 40 | this.uri = uri; 41 | } 42 | 43 | 44 | 45 | public HttpHeaders getHeaders() { 46 | return headers; 47 | } 48 | 49 | public void setHeaders(HttpHeaders headers) { 50 | this.headers = headers; 51 | } 52 | 53 | public byte[] getBody() { 54 | return body; 55 | } 56 | 57 | public void setBody(byte[] body) { 58 | this.body = body; 59 | } 60 | 61 | public Map> getParameters() { 62 | return parameters; 63 | } 64 | 65 | public void setParameters(Map> parameters) { 66 | this.parameters = parameters; 67 | } 68 | 69 | public Set getCookies() { 70 | return cookies; 71 | } 72 | 73 | public void setCookies(Set cookies) { 74 | this.cookies = cookies; 75 | } 76 | 77 | public boolean isNotAuthorized() { 78 | return notAuthorized; 79 | } 80 | 81 | public void setNotAuthorized(boolean notAuthorized) { 82 | this.notAuthorized = notAuthorized; 83 | } 84 | 85 | @Override 86 | public String toString() { 87 | return new Gson().toJson(this); 88 | } 89 | } -------------------------------------------------------------------------------- /chapter3/src/main/java/chapter3/recipe6/SimpleHttpResponse.java: -------------------------------------------------------------------------------- 1 | package chapter3.recipe6; 2 | 3 | import netty.cookbook.common.http.ContentTypePool; 4 | 5 | import com.google.gson.Gson; 6 | 7 | public class SimpleHttpResponse { 8 | protected int status = 200; 9 | protected String contentType = ContentTypePool.TEXT_UTF8; 10 | protected String head; 11 | protected String body; 12 | protected long time; 13 | 14 | public SimpleHttpResponse() { 15 | // TODO Auto-generated constructor stub 16 | } 17 | 18 | public SimpleHttpResponse(String data) { 19 | super(); 20 | this.body = data; 21 | } 22 | 23 | public int getStatus() { 24 | return status; 25 | } 26 | 27 | public void setStatus(int status) { 28 | this.status = status; 29 | } 30 | 31 | public String getContentType() { 32 | return contentType; 33 | } 34 | 35 | public void setContentType(String contentType) { 36 | this.contentType = contentType; 37 | } 38 | 39 | public String getHead() { 40 | return head; 41 | } 42 | 43 | public void setHead(String head) { 44 | this.head = head; 45 | } 46 | 47 | public String getBody() { 48 | return body; 49 | } 50 | 51 | public void setBody(String data) { 52 | this.body = data; 53 | } 54 | 55 | public long getTime() { 56 | return time; 57 | } 58 | 59 | public void setTime(long time) { 60 | this.time = time; 61 | } 62 | 63 | @Override 64 | public String toString() { 65 | return new Gson().toJson(this); 66 | } 67 | 68 | } -------------------------------------------------------------------------------- /chapter3/src/main/java/chapter3/recipe6/functions/Decorator.java: -------------------------------------------------------------------------------- 1 | package chapter3.recipe6.functions; 2 | 3 | import java.util.function.UnaryOperator; 4 | 5 | import chapter3.recipe6.SimpleHttpResponse; 6 | 7 | @FunctionalInterface 8 | public interface Decorator extends UnaryOperator{ 9 | 10 | } 11 | -------------------------------------------------------------------------------- /chapter3/src/main/java/chapter3/recipe6/functions/Filter.java: -------------------------------------------------------------------------------- 1 | package chapter3.recipe6.functions; 2 | 3 | import java.util.function.UnaryOperator; 4 | 5 | import chapter3.recipe6.SimpleHttpRequest; 6 | 7 | 8 | 9 | @FunctionalInterface 10 | public interface Filter extends UnaryOperator { 11 | 12 | 13 | } 14 | -------------------------------------------------------------------------------- /chapter3/src/main/java/chapter3/recipe6/functions/FinalProcessor.java: -------------------------------------------------------------------------------- 1 | package chapter3.recipe6.functions; 2 | 3 | import java.util.function.Function; 4 | 5 | import chapter3.recipe6.SimpleHttpRequest; 6 | import chapter3.recipe6.SimpleHttpResponse; 7 | 8 | @FunctionalInterface 9 | public interface FinalProcessor extends Function{ 10 | 11 | } 12 | -------------------------------------------------------------------------------- /chapter3/src/main/java/chapter3/recipe6/functions/Processor.java: -------------------------------------------------------------------------------- 1 | package chapter3.recipe6.functions; 2 | 3 | import java.util.function.Function; 4 | 5 | import chapter3.recipe6.SimpleHttpRequest; 6 | import chapter3.recipe6.SimpleHttpResponse; 7 | 8 | @FunctionalInterface 9 | public interface Processor extends Function{ 10 | 11 | } 12 | -------------------------------------------------------------------------------- /chapter3/src/main/java/log4j.properties: -------------------------------------------------------------------------------- 1 | # Root logger option 2 | log4j.rootLogger=INFO, stdout 3 | 4 | # Redirect log messages to console 5 | log4j.appender.stdout=org.apache.log4j.ConsoleAppender 6 | log4j.appender.stdout.Target=System.out 7 | log4j.appender.stdout.layout=org.apache.log4j.PatternLayout 8 | log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n 9 | 10 | # Redirect log messages to a log file, support file rolling. 11 | log4j.appender.file=org.apache.log4j.RollingFileAppender 12 | log4j.appender.file.File=./log/java-cookbook-demo 13 | log4j.appender.file.MaxFileSize=5MB 14 | log4j.appender.file.MaxBackupIndex=10 15 | log4j.appender.file.layout=org.apache.log4j.PatternLayout 16 | log4j.appender.file.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n -------------------------------------------------------------------------------- /chapter3/src/main/java/netty/cookbook/common/CallbackActor.java: -------------------------------------------------------------------------------- 1 | package netty.cookbook.common; 2 | 3 | import akka.actor.UntypedActor; 4 | 5 | public class CallbackActor extends UntypedActor { 6 | 7 | @Override 8 | public void onReceive(Object arg0) throws Exception { 9 | // TODO Auto-generated method stub 10 | 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /chapter3/src/main/java/netty/cookbook/common/CallbackProcessor.java: -------------------------------------------------------------------------------- 1 | package netty.cookbook.common; 2 | 3 | @FunctionalInterface 4 | public interface CallbackProcessor { 5 | public void process(Object obj); 6 | } -------------------------------------------------------------------------------- /chapter3/src/main/java/netty/cookbook/common/CharPool.java: -------------------------------------------------------------------------------- 1 | package netty.cookbook.common; 2 | 3 | public class CharPool { 4 | 5 | public static final char AMPERSAND = '&'; 6 | 7 | public static final char APOSTROPHE = '\''; 8 | 9 | public static final char AT = '@'; 10 | 11 | public static final char BACK_SLASH = '\\'; 12 | 13 | public static final char CLOSE_BRACKET = ']'; 14 | 15 | public static final char CLOSE_CURLY_BRACE = '}'; 16 | 17 | public static final char CLOSE_PARENTHESIS = ')'; 18 | 19 | public static final char COLON = ':'; 20 | 21 | public static final char COMMA = ','; 22 | 23 | public static final char DASH = '-'; 24 | 25 | public static final char EQUAL = '='; 26 | 27 | public static final char GREATER_THAN = '>'; 28 | 29 | public static final char FORWARD_SLASH = '/'; 30 | 31 | public static final char LESS_THAN = '<'; 32 | 33 | public static final char LOWER_CASE_E = 'e'; 34 | 35 | public static final char MINUS = '-'; 36 | 37 | public static final char NEW_LINE = '\n'; 38 | 39 | public static final char OPEN_BRACKET = '['; 40 | 41 | public static final char OPEN_CURLY_BRACE = '{'; 42 | 43 | public static final char OPEN_PARENTHESIS = '('; 44 | 45 | public static final char PERCENT = '%'; 46 | 47 | public static final char PERIOD = '.'; 48 | 49 | public static final char PIPE = '|'; 50 | 51 | public static final char PLUS = '+'; 52 | 53 | public static final char POUND = '#'; 54 | 55 | public static final char QUESTION = '?'; 56 | 57 | public static final char QUOTE = '\"'; 58 | 59 | public static final char RETURN = '\r'; 60 | 61 | public static final char SEMICOLON = ';'; 62 | 63 | public static final char SLASH = FORWARD_SLASH; 64 | 65 | public static final char SPACE = ' '; 66 | 67 | public static final char STAR = '*'; 68 | 69 | public static final char TILDE = '~'; 70 | 71 | public static final char UNDERLINE = '_'; 72 | 73 | public static final char UPPER_CASE_E = 'E'; 74 | 75 | public static final char TAB = '\t'; 76 | 77 | } 78 | -------------------------------------------------------------------------------- /chapter3/src/main/java/netty/cookbook/common/JsOptimizerUtil.java: -------------------------------------------------------------------------------- 1 | package netty.cookbook.common; 2 | 3 | import com.google.javascript.jscomp.CompilationLevel; 4 | import com.google.javascript.jscomp.Compiler; 5 | import com.google.javascript.jscomp.CompilerOptions; 6 | import com.google.javascript.jscomp.SourceFile; 7 | 8 | /** 9 | * Google Closure compiler Util 10 | * 11 | * @author Trieu.nguyen 12 | * 13 | */ 14 | public class JsOptimizerUtil { 15 | /** 16 | * @param code 17 | * JavaScript source code to compile. 18 | * @return The compiled version of the code. 19 | */ 20 | public static String compile(String code) { 21 | 22 | // System.out.println("------------------------"); 23 | // System.out.println(code); 24 | // System.out.println("------------------------"); 25 | 26 | Compiler compiler = new Compiler(); 27 | 28 | CompilerOptions options = new CompilerOptions(); 29 | // Advanced mode is used here, but additional options could be set, too. 30 | CompilationLevel.SIMPLE_OPTIMIZATIONS.setOptionsForCompilationLevel(options); 31 | 32 | // To get the complete set of externs, the logic in 33 | // CompilerRunner.getDefaultExterns() should be used here. 34 | SourceFile extern = SourceFile.fromCode("externs.js", ""); 35 | 36 | // The dummy input name "input.js" is used here so that any warnings or 37 | // errors will cite line numbers in terms of input.js. 38 | SourceFile input = SourceFile.fromCode("input.js", code); 39 | 40 | // compile() returns a Result, but it is not needed here. 41 | compiler.compile(extern, input, options); 42 | 43 | // The compiler is responsible for generating the compiled code; it is 44 | // not 45 | // accessible via the Result. 46 | return compiler.toSource(); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /chapter3/src/main/java/netty/cookbook/common/LogUtil.java: -------------------------------------------------------------------------------- 1 | package netty.cookbook.common; 2 | 3 | public class LogUtil { 4 | 5 | public static void println(Object obj){ 6 | System.out.println(obj); 7 | } 8 | 9 | public static void println(String obj){ 10 | System.out.println(obj); 11 | } 12 | 13 | 14 | } 15 | -------------------------------------------------------------------------------- /chapter3/src/main/java/netty/cookbook/common/NashornEngineUtil.java: -------------------------------------------------------------------------------- 1 | package netty.cookbook.common; 2 | 3 | import java.io.IOException; 4 | import java.nio.charset.StandardCharsets; 5 | import java.nio.file.Files; 6 | import java.nio.file.Paths; 7 | 8 | import javax.script.Compilable; 9 | import javax.script.CompiledScript; 10 | import javax.script.ScriptException; 11 | import javax.script.SimpleBindings; 12 | 13 | import jdk.nashorn.api.scripting.NashornScriptEngineFactory; 14 | import chapter3.recipe6.SimpleHttpRequest; 15 | import chapter3.recipe6.SimpleHttpResponse; 16 | 17 | public class NashornEngineUtil { 18 | private static final NashornScriptEngineFactory engineFactory = new NashornScriptEngineFactory(); 19 | 20 | public static SimpleHttpResponse process(SimpleHttpRequest httpRequest) 21 | throws NoSuchMethodException, ScriptException, IOException { 22 | CompiledScript compiled; 23 | Compilable engine; 24 | String scriptFilePath = "./src/main/resources/templates/js/script.js"; 25 | 26 | engine = (Compilable) engineFactory.getScriptEngine(); 27 | compiled = ((Compilable) engine).compile(Files.newBufferedReader(Paths.get(scriptFilePath),StandardCharsets.UTF_8)); 28 | 29 | SimpleBindings global = new SimpleBindings(); 30 | global.put("theReq", httpRequest); 31 | global.put("theResp", new SimpleHttpResponse()); 32 | 33 | Object result = compiled.eval(global); 34 | SimpleHttpResponse resp = (SimpleHttpResponse) result; 35 | return resp; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /chapter3/src/main/java/netty/cookbook/common/TcpChannelHandler.java: -------------------------------------------------------------------------------- 1 | package netty.cookbook.common; 2 | 3 | import io.netty.channel.ChannelHandlerContext; 4 | 5 | @FunctionalInterface 6 | public interface TcpChannelHandler { 7 | public void process(ChannelHandlerContext ctx, Object msg); 8 | } 9 | -------------------------------------------------------------------------------- /chapter3/src/main/java/netty/cookbook/common/UrlUtil.java: -------------------------------------------------------------------------------- 1 | package netty.cookbook.common; 2 | 3 | import java.net.MalformedURLException; 4 | import java.net.URL; 5 | 6 | public class UrlUtil { 7 | public final static String REGEX_FOR_ROOT_DOMAIN = ".*\\.(?=.*\\.)"; 8 | 9 | public static String getRootDomain(String fullUrl) throws MalformedURLException{ 10 | return new URL(fullUrl).getHost().replaceAll(REGEX_FOR_ROOT_DOMAIN, ""); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /chapter3/src/main/java/netty/cookbook/common/http/BasicHttpResponseHandler.java: -------------------------------------------------------------------------------- 1 | package netty.cookbook.common.http; 2 | 3 | import io.netty.handler.codec.http.HttpRequest; 4 | import io.netty.handler.codec.http.HttpResponse; 5 | import io.netty.handler.codec.http.QueryStringDecoder; 6 | 7 | public class BasicHttpResponseHandler implements HttpEventHandler { 8 | final String data; 9 | final int status; 10 | 11 | public BasicHttpResponseHandler(String data, int status) { 12 | super(); 13 | this.data = data; 14 | this.status = status; 15 | } 16 | 17 | public HttpResponse handle(HttpRequest req, QueryStringDecoder q) 18 | throws Exception { 19 | return HttpEventHandler.buildHttpResponse(data, status, ContentTypePool.TEXT_UTF8); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /chapter3/src/main/java/netty/cookbook/common/http/ContentTypePool.java: -------------------------------------------------------------------------------- 1 | package netty.cookbook.common.http; 2 | 3 | public class ContentTypePool { 4 | public static final String GIF = "image/gif"; 5 | public static final String TRACKING_GIF = GIF; 6 | public static final String JPEG = "image/jpeg"; 7 | 8 | public static final String JAVA_SCRIPT = "application/javascript; charset=utf-8"; 9 | public static final String XML = "application/xml; charset=utf-8"; 10 | public static final String JSON = "application/json; charset=utf-8"; 11 | 12 | public static final String TEXT_UTF8 = "text/plain; charset=UTF-8"; 13 | public static final String HTML_UTF8 = "text/html; charset=UTF-8"; 14 | } 15 | -------------------------------------------------------------------------------- /chapter3/src/main/java/netty/cookbook/common/http/HttpEventProcessor.java: -------------------------------------------------------------------------------- 1 | package netty.cookbook.common.http; 2 | 3 | import io.netty.handler.codec.http.HttpRequest; 4 | import io.netty.handler.codec.http.QueryStringDecoder; 5 | 6 | public class HttpEventProcessor { 7 | final HttpRequest req; 8 | final QueryStringDecoder query; 9 | 10 | public HttpEventProcessor(HttpRequest req, QueryStringDecoder query) { 11 | super(); 12 | this.req = req; 13 | this.query = query; 14 | } 15 | 16 | 17 | } 18 | -------------------------------------------------------------------------------- /chapter3/src/main/java/netty/cookbook/common/http/HttpOutputResource.java: -------------------------------------------------------------------------------- 1 | package netty.cookbook.common.http; 2 | 3 | import io.netty.buffer.ByteBuf; 4 | 5 | public class HttpOutputResource { 6 | ByteBuf byteBuf; 7 | long length; 8 | long lastModified; 9 | 10 | 11 | public HttpOutputResource(ByteBuf byteBuf, long lastModified) { 12 | super(); 13 | this.byteBuf = byteBuf; 14 | this.length = byteBuf.readableBytes(); 15 | this.lastModified = lastModified; 16 | } 17 | 18 | public ByteBuf getByteBuf() { 19 | return byteBuf; 20 | } 21 | 22 | public void setByteBuf(ByteBuf byteBuf) { 23 | this.byteBuf = byteBuf; 24 | } 25 | 26 | public long getLength() { 27 | return length; 28 | } 29 | 30 | public void setLength(long length) { 31 | this.length = length; 32 | } 33 | 34 | public long getLastModified() { 35 | return lastModified; 36 | } 37 | 38 | public void setLastModified(long lastModified) { 39 | this.lastModified = lastModified; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /chapter3/src/main/java/netty/cookbook/common/redis/RedisCommand.java: -------------------------------------------------------------------------------- 1 | package netty.cookbook.common.redis; 2 | 3 | import netty.cookbook.common.StringPool; 4 | import redis.clients.jedis.Jedis; 5 | import redis.clients.jedis.ShardedJedis; 6 | import redis.clients.jedis.ShardedJedisPool; 7 | import redis.clients.jedis.exceptions.JedisException; 8 | 9 | public abstract class RedisCommand { 10 | protected ShardedJedisPool jedisPool; 11 | protected ShardedJedis shardedJedis = null; 12 | protected Jedis jedis = null; 13 | 14 | public RedisCommand(ShardedJedisPool jedisPool) { 15 | super(); 16 | if (jedisPool == null) { 17 | throw new IllegalArgumentException("jedisPool is NULL!"); 18 | } 19 | this.jedisPool = jedisPool; 20 | } 21 | 22 | public T execute() { 23 | boolean commited = false; 24 | T rs = null; 25 | try { 26 | shardedJedis = jedisPool.getResource(); 27 | if (shardedJedis != null) { 28 | jedis = shardedJedis.getShard(StringPool.BLANK); 29 | rs = build(); 30 | commited = true; 31 | } 32 | } catch (Exception e) { 33 | e.printStackTrace(); 34 | } finally { 35 | freeRedisResource(jedisPool, shardedJedis, commited); 36 | } 37 | return rs; 38 | } 39 | 40 | public static void freeRedisResource(ShardedJedisPool jedisPool, ShardedJedis shardedJedis, boolean isCommited){ 41 | if (shardedJedis != null && jedisPool != null) { 42 | if (isCommited) { 43 | jedisPool.returnResource(shardedJedis); 44 | } else { 45 | jedisPool.returnBrokenResource(shardedJedis); 46 | } 47 | } 48 | } 49 | 50 | //define the logic at implementer 51 | protected abstract T build() throws JedisException; 52 | } -------------------------------------------------------------------------------- /chapter3/src/main/java/netty/cookbook/common/redis/RedisInfo.java: -------------------------------------------------------------------------------- 1 | package netty.cookbook.common.redis; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | import redis.clients.jedis.JedisShardInfo; 7 | import redis.clients.jedis.ShardedJedisPool; 8 | 9 | public class RedisInfo { 10 | public static final String LOCALHOST_STR = "localhost"; 11 | 12 | private String host; 13 | private int port; 14 | private String auth; 15 | private ShardedJedisPool shardedJedisPool; 16 | 17 | protected void initThePool(){ 18 | List shardInfos = new ArrayList(1); 19 | shardInfos.add(new JedisShardInfo(getHost(), getPort(), 0)); 20 | shardedJedisPool = new ShardedJedisPool(RedisConnectionPoolConfig.getJedisPoolConfigInstance(), shardInfos); 21 | } 22 | 23 | public RedisInfo(String host, int port) { 24 | this.host = host; 25 | this.port = port; 26 | initThePool(); 27 | } 28 | 29 | public RedisInfo(String host, int port,String auth) { 30 | this.host = host; 31 | this.port = port; 32 | this.auth = auth; 33 | initThePool(); 34 | } 35 | 36 | public String getHost() { 37 | return host; 38 | } 39 | 40 | public int getPort() { 41 | return port; 42 | } 43 | 44 | public String getAuth() { 45 | return auth; 46 | } 47 | 48 | @Override 49 | public boolean equals(Object obj) { 50 | if (obj instanceof RedisInfo) { 51 | RedisInfo hp = (RedisInfo) obj; 52 | 53 | String thisHost = convertHost(host); 54 | String hpHost = convertHost(hp.host); 55 | return port == hp.port && thisHost.equals(hpHost); 56 | 57 | } 58 | 59 | return false; 60 | } 61 | 62 | public ShardedJedisPool getShardedJedisPool() { 63 | return shardedJedisPool; 64 | } 65 | 66 | @Override 67 | public String toString() { 68 | return host + ":" + port; 69 | } 70 | 71 | private String convertHost(String host) { 72 | if (host.equals("127.0.0.1")) 73 | return LOCALHOST_STR; 74 | else if (host.equals("::1")) 75 | return LOCALHOST_STR; 76 | 77 | return host; 78 | } 79 | } -------------------------------------------------------------------------------- /chapter3/src/main/resources/templates/hello-view.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Hello SpringMVC with Netty 5 | 6 | 8 | 9 | 10 |

11 | 12 |
13 |
14 | 28 | 29 | -------------------------------------------------------------------------------- /chapter3/src/main/resources/templates/js/script.js: -------------------------------------------------------------------------------- 1 | var fun1 = function(name) { 2 | print('Hi there from Javascript, ' + name); 3 | return "greetings from javascript"; 4 | }; 5 | 6 | var router = function (req, resp) { 7 | //print("req: " + Object.prototype.toString.call(req)); 8 | resp.data = "hello from JS Nashorn Engine"; 9 | //resp.time = new Date().getTime(); 10 | return resp; 11 | }; 12 | 13 | router(theReq, theResp) 14 | 15 | /* 16 | load('http://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.6.0/underscore-min.js'); 17 | 18 | var odds = _.filter([1, 2, 3, 4, 5, 6], function (num) { 19 | return num % 2 == 1; 20 | }); 21 | 22 | print(odds); // 1, 3, 5 23 | */ -------------------------------------------------------------------------------- /chapter4/.gitignore: -------------------------------------------------------------------------------- 1 | /bin/ 2 | /build/ 3 | -------------------------------------------------------------------------------- /chapter4/.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | chapter4 4 | 5 | 6 | 7 | 8 | 9 | org.eclipse.jdt.core.javabuilder 10 | 11 | 12 | 13 | 14 | 15 | org.springsource.ide.eclipse.gradle.core.nature 16 | org.eclipse.jdt.core.javanature 17 | 18 | 19 | -------------------------------------------------------------------------------- /chapter4/README.md: -------------------------------------------------------------------------------- 1 | Netty Cookbook - chapter 4 code -------------------------------------------------------------------------------- /chapter4/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'java' 2 | apply plugin: 'eclipse' 3 | 4 | sourceCompatibility = 1.8 5 | 6 | version = '1.0' 7 | 8 | repositories { 9 | mavenCentral() 10 | } 11 | 12 | dependencies { 13 | compile ( 14 | // common 15 | 'io.netty:netty-all:4.0.25.Final' 16 | ,'commons-io:commons-io:2.4' 17 | ,'org.apache.commons:commons-lang3:3.3.2' 18 | ,'log4j:log4j:1.2.17' 19 | ,'org.slf4j:slf4j-log4j12:1.7.7' 20 | ,'org.yaml:snakeyaml:1.14' 21 | 22 | ,'com.google.code.gson:gson:2.3' 23 | ,'com.google.guava:guava:18.0' 24 | ,'org.twitter4j:twitter4j-core:4.0.2' 25 | ,'org.twitter4j:twitter4j-stream:4.0.2' 26 | ,'redis.clients:jedis:2.6.2' 27 | ,'com.github.jknack:handlebars:2.0.0' 28 | 29 | ,'io.reactivex:rxnetty:0.4.6' 30 | 31 | ) 32 | testCompile group: 'junit', name: 'junit', version: '4.11' 33 | } 34 | -------------------------------------------------------------------------------- /chapter4/configs/redis-connection-pool-configs.json: -------------------------------------------------------------------------------- 1 | { 2 | maxTotal : 3000, 3 | maxIdle : 20, 4 | minIdle : 2, 5 | maxWaitMillis : 5000; 6 | numTestsPerEvictionRun : 10, 7 | testOnBorrow : true, 8 | testOnReturn : true, 9 | testWhileIdle : true, 10 | timeBetweenEvictionRunsMillis : 60000 11 | } -------------------------------------------------------------------------------- /chapter4/src/main/java/chapter4/recipe1/WebSocketServer.java: -------------------------------------------------------------------------------- 1 | package chapter4.recipe1; 2 | 3 | 4 | /** 5 | * @author toddf 6 | * @since June 29, 2012 7 | */ 8 | public class WebSocketServer { 9 | 10 | 11 | public static void main(String[] args) { 12 | } 13 | } -------------------------------------------------------------------------------- /chapter4/src/main/java/chapter4/recipe2/RealtimeWebSocketIO.java: -------------------------------------------------------------------------------- 1 | package chapter4.recipe2; 2 | 3 | public class RealtimeWebSocketIO { 4 | 5 | } 6 | -------------------------------------------------------------------------------- /chapter4/src/main/java/chapter4/recipe3/ChatServerWithSTOMP.java: -------------------------------------------------------------------------------- 1 | package chapter4.recipe3; 2 | 3 | public class ChatServerWithSTOMP { 4 | 5 | } 6 | -------------------------------------------------------------------------------- /chapter4/src/main/java/chapter4/recipe4/RealtimeWidgetServer.java: -------------------------------------------------------------------------------- 1 | package chapter4.recipe4; 2 | 3 | public class RealtimeWidgetServer { 4 | 5 | } 6 | -------------------------------------------------------------------------------- /chapter4/src/main/java/log4j.properties: -------------------------------------------------------------------------------- 1 | # Root logger option 2 | log4j.rootLogger=INFO, stdout 3 | 4 | # Redirect log messages to console 5 | log4j.appender.stdout=org.apache.log4j.ConsoleAppender 6 | log4j.appender.stdout.Target=System.out 7 | log4j.appender.stdout.layout=org.apache.log4j.PatternLayout 8 | log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n 9 | 10 | # Redirect log messages to a log file, support file rolling. 11 | log4j.appender.file=org.apache.log4j.RollingFileAppender 12 | log4j.appender.file.File=./log/java-cookbook-demo 13 | log4j.appender.file.MaxFileSize=5MB 14 | log4j.appender.file.MaxBackupIndex=10 15 | log4j.appender.file.layout=org.apache.log4j.PatternLayout 16 | log4j.appender.file.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n -------------------------------------------------------------------------------- /chapter4/src/main/java/netty/cookbook/common/CallbackProcessor.java: -------------------------------------------------------------------------------- 1 | package netty.cookbook.common; 2 | 3 | @FunctionalInterface 4 | public interface CallbackProcessor { 5 | public void process(Object obj); 6 | } -------------------------------------------------------------------------------- /chapter4/src/main/java/netty/cookbook/common/CharPool.java: -------------------------------------------------------------------------------- 1 | package netty.cookbook.common; 2 | 3 | public class CharPool { 4 | 5 | public static final char AMPERSAND = '&'; 6 | 7 | public static final char APOSTROPHE = '\''; 8 | 9 | public static final char AT = '@'; 10 | 11 | public static final char BACK_SLASH = '\\'; 12 | 13 | public static final char CLOSE_BRACKET = ']'; 14 | 15 | public static final char CLOSE_CURLY_BRACE = '}'; 16 | 17 | public static final char CLOSE_PARENTHESIS = ')'; 18 | 19 | public static final char COLON = ':'; 20 | 21 | public static final char COMMA = ','; 22 | 23 | public static final char DASH = '-'; 24 | 25 | public static final char EQUAL = '='; 26 | 27 | public static final char GREATER_THAN = '>'; 28 | 29 | public static final char FORWARD_SLASH = '/'; 30 | 31 | public static final char LESS_THAN = '<'; 32 | 33 | public static final char LOWER_CASE_E = 'e'; 34 | 35 | public static final char MINUS = '-'; 36 | 37 | public static final char NEW_LINE = '\n'; 38 | 39 | public static final char OPEN_BRACKET = '['; 40 | 41 | public static final char OPEN_CURLY_BRACE = '{'; 42 | 43 | public static final char OPEN_PARENTHESIS = '('; 44 | 45 | public static final char PERCENT = '%'; 46 | 47 | public static final char PERIOD = '.'; 48 | 49 | public static final char PIPE = '|'; 50 | 51 | public static final char PLUS = '+'; 52 | 53 | public static final char POUND = '#'; 54 | 55 | public static final char QUESTION = '?'; 56 | 57 | public static final char QUOTE = '\"'; 58 | 59 | public static final char RETURN = '\r'; 60 | 61 | public static final char SEMICOLON = ';'; 62 | 63 | public static final char SLASH = FORWARD_SLASH; 64 | 65 | public static final char SPACE = ' '; 66 | 67 | public static final char STAR = '*'; 68 | 69 | public static final char TILDE = '~'; 70 | 71 | public static final char UNDERLINE = '_'; 72 | 73 | public static final char UPPER_CASE_E = 'E'; 74 | 75 | public static final char TAB = '\t'; 76 | 77 | } 78 | -------------------------------------------------------------------------------- /chapter4/src/main/java/netty/cookbook/common/LogUtil.java: -------------------------------------------------------------------------------- 1 | package netty.cookbook.common; 2 | 3 | public class LogUtil { 4 | 5 | public static void println(Object obj){ 6 | System.out.println(obj); 7 | } 8 | 9 | public static void println(String obj){ 10 | System.out.println(obj); 11 | } 12 | 13 | 14 | } 15 | -------------------------------------------------------------------------------- /chapter4/src/main/java/netty/cookbook/common/TcpChannelHandler.java: -------------------------------------------------------------------------------- 1 | package netty.cookbook.common; 2 | 3 | import io.netty.channel.ChannelHandlerContext; 4 | 5 | @FunctionalInterface 6 | public interface TcpChannelHandler { 7 | public void process(ChannelHandlerContext ctx, Object msg); 8 | } 9 | -------------------------------------------------------------------------------- /chapter4/src/main/java/netty/cookbook/common/UrlUtil.java: -------------------------------------------------------------------------------- 1 | package netty.cookbook.common; 2 | 3 | import java.net.MalformedURLException; 4 | import java.net.URL; 5 | 6 | public class UrlUtil { 7 | public final static String REGEX_FOR_ROOT_DOMAIN = ".*\\.(?=.*\\.)"; 8 | 9 | public static String getRootDomain(String fullUrl) throws MalformedURLException{ 10 | return new URL(fullUrl).getHost().replaceAll(REGEX_FOR_ROOT_DOMAIN, ""); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /chapter4/src/main/java/netty/cookbook/common/http/ContentTypePool.java: -------------------------------------------------------------------------------- 1 | package netty.cookbook.common.http; 2 | 3 | public class ContentTypePool { 4 | public static final String GIF = "image/gif"; 5 | public static final String TRACKING_GIF = GIF; 6 | public static final String JPEG = "image/jpeg"; 7 | 8 | public static final String JAVA_SCRIPT = "application/javascript; charset=utf-8"; 9 | public static final String XML = "application/xml; charset=utf-8"; 10 | public static final String JSON = "application/json; charset=utf-8"; 11 | 12 | public static final String TEXT_UTF8 = "text/plain; charset=UTF-8"; 13 | public static final String HTML_UTF8 = "text/html; charset=UTF-8"; 14 | } 15 | -------------------------------------------------------------------------------- /chapter4/src/main/java/netty/cookbook/common/http/HttpOutputResource.java: -------------------------------------------------------------------------------- 1 | package netty.cookbook.common.http; 2 | 3 | import io.netty.buffer.ByteBuf; 4 | 5 | public class HttpOutputResource { 6 | ByteBuf byteBuf; 7 | long length; 8 | long lastModified; 9 | 10 | 11 | public HttpOutputResource(ByteBuf byteBuf, long lastModified) { 12 | super(); 13 | this.byteBuf = byteBuf; 14 | this.length = byteBuf.readableBytes(); 15 | this.lastModified = lastModified; 16 | } 17 | 18 | public ByteBuf getByteBuf() { 19 | return byteBuf; 20 | } 21 | 22 | public void setByteBuf(ByteBuf byteBuf) { 23 | this.byteBuf = byteBuf; 24 | } 25 | 26 | public long getLength() { 27 | return length; 28 | } 29 | 30 | public void setLength(long length) { 31 | this.length = length; 32 | } 33 | 34 | public long getLastModified() { 35 | return lastModified; 36 | } 37 | 38 | public void setLastModified(long lastModified) { 39 | this.lastModified = lastModified; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /chapter4/src/main/java/netty/cookbook/common/redis/RedisCommand.java: -------------------------------------------------------------------------------- 1 | package netty.cookbook.common.redis; 2 | 3 | import netty.cookbook.common.StringPool; 4 | import redis.clients.jedis.Jedis; 5 | import redis.clients.jedis.ShardedJedis; 6 | import redis.clients.jedis.ShardedJedisPool; 7 | import redis.clients.jedis.exceptions.JedisException; 8 | 9 | public abstract class RedisCommand { 10 | protected ShardedJedisPool jedisPool; 11 | protected ShardedJedis shardedJedis = null; 12 | protected Jedis jedis = null; 13 | 14 | public RedisCommand(ShardedJedisPool jedisPool) { 15 | super(); 16 | if (jedisPool == null) { 17 | throw new IllegalArgumentException("jedisPool is NULL!"); 18 | } 19 | this.jedisPool = jedisPool; 20 | } 21 | 22 | public T execute() { 23 | boolean commited = false; 24 | T rs = null; 25 | try { 26 | shardedJedis = jedisPool.getResource(); 27 | if (shardedJedis != null) { 28 | jedis = shardedJedis.getShard(StringPool.BLANK); 29 | rs = build(); 30 | commited = true; 31 | } 32 | } catch (Exception e) { 33 | e.printStackTrace(); 34 | } finally { 35 | freeRedisResource(jedisPool, shardedJedis, commited); 36 | } 37 | return rs; 38 | } 39 | 40 | public static void freeRedisResource(ShardedJedisPool jedisPool, ShardedJedis shardedJedis, boolean isCommited){ 41 | if (shardedJedis != null && jedisPool != null) { 42 | if (isCommited) { 43 | jedisPool.returnResource(shardedJedis); 44 | } else { 45 | jedisPool.returnBrokenResource(shardedJedis); 46 | } 47 | } 48 | } 49 | 50 | //define the logic at implementer 51 | protected abstract T build() throws JedisException; 52 | } -------------------------------------------------------------------------------- /chapter4/src/main/java/netty/cookbook/common/redis/RedisInfo.java: -------------------------------------------------------------------------------- 1 | package netty.cookbook.common.redis; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | import redis.clients.jedis.JedisShardInfo; 7 | import redis.clients.jedis.ShardedJedisPool; 8 | 9 | public class RedisInfo { 10 | public static final String LOCALHOST_STR = "localhost"; 11 | 12 | private String host; 13 | private int port; 14 | private String auth; 15 | private ShardedJedisPool shardedJedisPool; 16 | 17 | protected void initThePool(){ 18 | List shardInfos = new ArrayList(1); 19 | shardInfos.add(new JedisShardInfo(getHost(), getPort(), 0)); 20 | shardedJedisPool = new ShardedJedisPool(RedisConnectionPoolConfig.getJedisPoolConfigInstance(), shardInfos); 21 | } 22 | 23 | public RedisInfo(String host, int port) { 24 | this.host = host; 25 | this.port = port; 26 | initThePool(); 27 | } 28 | 29 | public RedisInfo(String host, int port,String auth) { 30 | this.host = host; 31 | this.port = port; 32 | this.auth = auth; 33 | initThePool(); 34 | } 35 | 36 | public String getHost() { 37 | return host; 38 | } 39 | 40 | public int getPort() { 41 | return port; 42 | } 43 | 44 | public String getAuth() { 45 | return auth; 46 | } 47 | 48 | @Override 49 | public boolean equals(Object obj) { 50 | if (obj instanceof RedisInfo) { 51 | RedisInfo hp = (RedisInfo) obj; 52 | 53 | String thisHost = convertHost(host); 54 | String hpHost = convertHost(hp.host); 55 | return port == hp.port && thisHost.equals(hpHost); 56 | 57 | } 58 | 59 | return false; 60 | } 61 | 62 | public ShardedJedisPool getShardedJedisPool() { 63 | return shardedJedisPool; 64 | } 65 | 66 | @Override 67 | public String toString() { 68 | return host + ":" + port; 69 | } 70 | 71 | private String convertHost(String host) { 72 | if (host.equals("127.0.0.1")) 73 | return LOCALHOST_STR; 74 | else if (host.equals("::1")) 75 | return LOCALHOST_STR; 76 | 77 | return host; 78 | } 79 | } -------------------------------------------------------------------------------- /chapter5/.gitignore: -------------------------------------------------------------------------------- 1 | /bin/ 2 | /build/ 3 | -------------------------------------------------------------------------------- /chapter5/.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | chapter5 4 | 5 | 6 | 7 | 8 | 9 | org.eclipse.jdt.core.javabuilder 10 | 11 | 12 | 13 | 14 | 15 | org.springsource.ide.eclipse.gradle.core.nature 16 | org.eclipse.jdt.core.javanature 17 | 18 | 19 | -------------------------------------------------------------------------------- /chapter5/README.md: -------------------------------------------------------------------------------- 1 | Netty Cookbook - chapter 5 code -------------------------------------------------------------------------------- /chapter5/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'java' 2 | apply plugin: 'eclipse' 3 | 4 | sourceCompatibility = 1.8 5 | 6 | version = '1.0' 7 | 8 | repositories { 9 | mavenCentral() 10 | } 11 | 12 | dependencies { 13 | compile ( 14 | // common 15 | 'io.netty:netty-all:4.0.25.Final' 16 | ,'commons-io:commons-io:2.4' 17 | ,'org.apache.commons:commons-lang3:3.3.2' 18 | ,'log4j:log4j:1.2.17' 19 | ,'org.slf4j:slf4j-log4j12:1.7.7' 20 | ,'org.yaml:snakeyaml:1.14' 21 | 22 | ,'com.google.code.gson:gson:2.3' 23 | ,'com.google.guava:guava:18.0' 24 | ,'org.twitter4j:twitter4j-core:4.0.2' 25 | ,'org.twitter4j:twitter4j-stream:4.0.2' 26 | ,'redis.clients:jedis:2.6.2' 27 | ,'com.github.jknack:handlebars:2.0.0' 28 | 29 | ) 30 | testCompile group: 'junit', name: 'junit', version: '4.11' 31 | } 32 | -------------------------------------------------------------------------------- /chapter5/src/main/java/chapter4/recipe1/WebSocketServer.java: -------------------------------------------------------------------------------- 1 | package chapter4.recipe1; 2 | 3 | 4 | /** 5 | * @author toddf 6 | * @since June 29, 2012 7 | */ 8 | public class WebSocketServer { 9 | 10 | 11 | public static void main(String[] args) { 12 | } 13 | } -------------------------------------------------------------------------------- /chapter5/src/main/java/chapter4/recipe2/RealtimeWebSocketIO.java: -------------------------------------------------------------------------------- 1 | package chapter4.recipe2; 2 | 3 | public class RealtimeWebSocketIO { 4 | 5 | } 6 | -------------------------------------------------------------------------------- /chapter5/src/main/java/chapter4/recipe3/ChatServerWithSTOMP.java: -------------------------------------------------------------------------------- 1 | package chapter4.recipe3; 2 | 3 | public class ChatServerWithSTOMP { 4 | 5 | } 6 | -------------------------------------------------------------------------------- /chapter5/src/main/java/chapter4/recipe4/RealtimeWidgetServer.java: -------------------------------------------------------------------------------- 1 | package chapter4.recipe4; 2 | 3 | public class RealtimeWidgetServer { 4 | 5 | } 6 | -------------------------------------------------------------------------------- /chapter5/src/main/java/log4j.properties: -------------------------------------------------------------------------------- 1 | # Root logger option 2 | log4j.rootLogger=INFO, stdout 3 | 4 | # Redirect log messages to console 5 | log4j.appender.stdout=org.apache.log4j.ConsoleAppender 6 | log4j.appender.stdout.Target=System.out 7 | log4j.appender.stdout.layout=org.apache.log4j.PatternLayout 8 | log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n 9 | 10 | # Redirect log messages to a log file, support file rolling. 11 | log4j.appender.file=org.apache.log4j.RollingFileAppender 12 | log4j.appender.file.File=./log/java-cookbook-demo 13 | log4j.appender.file.MaxFileSize=5MB 14 | log4j.appender.file.MaxBackupIndex=10 15 | log4j.appender.file.layout=org.apache.log4j.PatternLayout 16 | log4j.appender.file.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n -------------------------------------------------------------------------------- /chapter5/src/main/java/netty/cookbook/common/CallbackProcessor.java: -------------------------------------------------------------------------------- 1 | package netty.cookbook.common; 2 | 3 | @FunctionalInterface 4 | public interface CallbackProcessor { 5 | public void process(Object obj); 6 | } -------------------------------------------------------------------------------- /chapter5/src/main/java/netty/cookbook/common/CharPool.java: -------------------------------------------------------------------------------- 1 | package netty.cookbook.common; 2 | 3 | public class CharPool { 4 | 5 | public static final char AMPERSAND = '&'; 6 | 7 | public static final char APOSTROPHE = '\''; 8 | 9 | public static final char AT = '@'; 10 | 11 | public static final char BACK_SLASH = '\\'; 12 | 13 | public static final char CLOSE_BRACKET = ']'; 14 | 15 | public static final char CLOSE_CURLY_BRACE = '}'; 16 | 17 | public static final char CLOSE_PARENTHESIS = ')'; 18 | 19 | public static final char COLON = ':'; 20 | 21 | public static final char COMMA = ','; 22 | 23 | public static final char DASH = '-'; 24 | 25 | public static final char EQUAL = '='; 26 | 27 | public static final char GREATER_THAN = '>'; 28 | 29 | public static final char FORWARD_SLASH = '/'; 30 | 31 | public static final char LESS_THAN = '<'; 32 | 33 | public static final char LOWER_CASE_E = 'e'; 34 | 35 | public static final char MINUS = '-'; 36 | 37 | public static final char NEW_LINE = '\n'; 38 | 39 | public static final char OPEN_BRACKET = '['; 40 | 41 | public static final char OPEN_CURLY_BRACE = '{'; 42 | 43 | public static final char OPEN_PARENTHESIS = '('; 44 | 45 | public static final char PERCENT = '%'; 46 | 47 | public static final char PERIOD = '.'; 48 | 49 | public static final char PIPE = '|'; 50 | 51 | public static final char PLUS = '+'; 52 | 53 | public static final char POUND = '#'; 54 | 55 | public static final char QUESTION = '?'; 56 | 57 | public static final char QUOTE = '\"'; 58 | 59 | public static final char RETURN = '\r'; 60 | 61 | public static final char SEMICOLON = ';'; 62 | 63 | public static final char SLASH = FORWARD_SLASH; 64 | 65 | public static final char SPACE = ' '; 66 | 67 | public static final char STAR = '*'; 68 | 69 | public static final char TILDE = '~'; 70 | 71 | public static final char UNDERLINE = '_'; 72 | 73 | public static final char UPPER_CASE_E = 'E'; 74 | 75 | public static final char TAB = '\t'; 76 | 77 | } 78 | -------------------------------------------------------------------------------- /chapter5/src/main/java/netty/cookbook/common/LogUtil.java: -------------------------------------------------------------------------------- 1 | package netty.cookbook.common; 2 | 3 | public class LogUtil { 4 | 5 | public static void println(Object obj){ 6 | System.out.println(obj); 7 | } 8 | 9 | public static void println(String obj){ 10 | System.out.println(obj); 11 | } 12 | 13 | 14 | } 15 | -------------------------------------------------------------------------------- /chapter5/src/main/java/netty/cookbook/common/TcpChannelHandler.java: -------------------------------------------------------------------------------- 1 | package netty.cookbook.common; 2 | 3 | import io.netty.channel.ChannelHandlerContext; 4 | 5 | @FunctionalInterface 6 | public interface TcpChannelHandler { 7 | public void process(ChannelHandlerContext ctx, Object msg); 8 | } 9 | -------------------------------------------------------------------------------- /chapter5/src/main/java/netty/cookbook/common/UrlUtil.java: -------------------------------------------------------------------------------- 1 | package netty.cookbook.common; 2 | 3 | import java.net.MalformedURLException; 4 | import java.net.URL; 5 | 6 | public class UrlUtil { 7 | public final static String REGEX_FOR_ROOT_DOMAIN = ".*\\.(?=.*\\.)"; 8 | 9 | public static String getRootDomain(String fullUrl) throws MalformedURLException{ 10 | return new URL(fullUrl).getHost().replaceAll(REGEX_FOR_ROOT_DOMAIN, ""); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /chapter5/src/main/java/netty/cookbook/common/http/ContentTypePool.java: -------------------------------------------------------------------------------- 1 | package netty.cookbook.common.http; 2 | 3 | public class ContentTypePool { 4 | public static final String GIF = "image/gif"; 5 | public static final String TRACKING_GIF = GIF; 6 | public static final String JPEG = "image/jpeg"; 7 | 8 | public static final String JAVA_SCRIPT = "application/javascript; charset=utf-8"; 9 | public static final String XML = "application/xml; charset=utf-8"; 10 | public static final String JSON = "application/json; charset=utf-8"; 11 | 12 | public static final String TEXT_UTF8 = "text/plain; charset=UTF-8"; 13 | public static final String HTML_UTF8 = "text/html; charset=UTF-8"; 14 | } 15 | -------------------------------------------------------------------------------- /chapter5/src/main/java/netty/cookbook/common/http/HttpOutputResource.java: -------------------------------------------------------------------------------- 1 | package netty.cookbook.common.http; 2 | 3 | import io.netty.buffer.ByteBuf; 4 | 5 | public class HttpOutputResource { 6 | ByteBuf byteBuf; 7 | long length; 8 | long lastModified; 9 | 10 | 11 | public HttpOutputResource(ByteBuf byteBuf, long lastModified) { 12 | super(); 13 | this.byteBuf = byteBuf; 14 | this.length = byteBuf.readableBytes(); 15 | this.lastModified = lastModified; 16 | } 17 | 18 | public ByteBuf getByteBuf() { 19 | return byteBuf; 20 | } 21 | 22 | public void setByteBuf(ByteBuf byteBuf) { 23 | this.byteBuf = byteBuf; 24 | } 25 | 26 | public long getLength() { 27 | return length; 28 | } 29 | 30 | public void setLength(long length) { 31 | this.length = length; 32 | } 33 | 34 | public long getLastModified() { 35 | return lastModified; 36 | } 37 | 38 | public void setLastModified(long lastModified) { 39 | this.lastModified = lastModified; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /chapter5/src/main/java/netty/cookbook/common/redis/RedisCommand.java: -------------------------------------------------------------------------------- 1 | package netty.cookbook.common.redis; 2 | 3 | import netty.cookbook.common.StringPool; 4 | import redis.clients.jedis.Jedis; 5 | import redis.clients.jedis.ShardedJedis; 6 | import redis.clients.jedis.ShardedJedisPool; 7 | import redis.clients.jedis.exceptions.JedisException; 8 | 9 | public abstract class RedisCommand { 10 | protected ShardedJedisPool jedisPool; 11 | protected ShardedJedis shardedJedis = null; 12 | protected Jedis jedis = null; 13 | 14 | public RedisCommand(ShardedJedisPool jedisPool) { 15 | super(); 16 | if (jedisPool == null) { 17 | throw new IllegalArgumentException("jedisPool is NULL!"); 18 | } 19 | this.jedisPool = jedisPool; 20 | } 21 | 22 | public T execute() { 23 | boolean commited = false; 24 | T rs = null; 25 | try { 26 | shardedJedis = jedisPool.getResource(); 27 | if (shardedJedis != null) { 28 | jedis = shardedJedis.getShard(StringPool.BLANK); 29 | rs = build(); 30 | commited = true; 31 | } 32 | } catch (Exception e) { 33 | e.printStackTrace(); 34 | } finally { 35 | freeRedisResource(jedisPool, shardedJedis, commited); 36 | } 37 | return rs; 38 | } 39 | 40 | public static void freeRedisResource(ShardedJedisPool jedisPool, ShardedJedis shardedJedis, boolean isCommited){ 41 | if (shardedJedis != null && jedisPool != null) { 42 | if (isCommited) { 43 | jedisPool.returnResource(shardedJedis); 44 | } else { 45 | jedisPool.returnBrokenResource(shardedJedis); 46 | } 47 | } 48 | } 49 | 50 | //define the logic at implementer 51 | protected abstract T build() throws JedisException; 52 | } -------------------------------------------------------------------------------- /chapter5/src/main/java/netty/cookbook/common/redis/RedisInfo.java: -------------------------------------------------------------------------------- 1 | package netty.cookbook.common.redis; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | import redis.clients.jedis.JedisShardInfo; 7 | import redis.clients.jedis.ShardedJedisPool; 8 | 9 | public class RedisInfo { 10 | public static final String LOCALHOST_STR = "localhost"; 11 | 12 | private String host; 13 | private int port; 14 | private String auth; 15 | private ShardedJedisPool shardedJedisPool; 16 | 17 | protected void initThePool(){ 18 | List shardInfos = new ArrayList(1); 19 | shardInfos.add(new JedisShardInfo(getHost(), getPort(), 0)); 20 | shardedJedisPool = new ShardedJedisPool(RedisConnectionPoolConfig.getJedisPoolConfigInstance(), shardInfos); 21 | } 22 | 23 | public RedisInfo(String host, int port) { 24 | this.host = host; 25 | this.port = port; 26 | initThePool(); 27 | } 28 | 29 | public RedisInfo(String host, int port,String auth) { 30 | this.host = host; 31 | this.port = port; 32 | this.auth = auth; 33 | initThePool(); 34 | } 35 | 36 | public String getHost() { 37 | return host; 38 | } 39 | 40 | public int getPort() { 41 | return port; 42 | } 43 | 44 | public String getAuth() { 45 | return auth; 46 | } 47 | 48 | @Override 49 | public boolean equals(Object obj) { 50 | if (obj instanceof RedisInfo) { 51 | RedisInfo hp = (RedisInfo) obj; 52 | 53 | String thisHost = convertHost(host); 54 | String hpHost = convertHost(hp.host); 55 | return port == hp.port && thisHost.equals(hpHost); 56 | 57 | } 58 | 59 | return false; 60 | } 61 | 62 | public ShardedJedisPool getShardedJedisPool() { 63 | return shardedJedisPool; 64 | } 65 | 66 | @Override 67 | public String toString() { 68 | return host + ":" + port; 69 | } 70 | 71 | private String convertHost(String host) { 72 | if (host.equals("127.0.0.1")) 73 | return LOCALHOST_STR; 74 | else if (host.equals("::1")) 75 | return LOCALHOST_STR; 76 | 77 | return host; 78 | } 79 | } -------------------------------------------------------------------------------- /chapter6/.gitignore: -------------------------------------------------------------------------------- 1 | /bin/ 2 | /build/ 3 | -------------------------------------------------------------------------------- /chapter6/.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | chapter5 4 | 5 | 6 | 7 | 8 | 9 | org.eclipse.jdt.core.javabuilder 10 | 11 | 12 | 13 | 14 | 15 | org.springsource.ide.eclipse.gradle.core.nature 16 | org.eclipse.jdt.core.javanature 17 | 18 | 19 | -------------------------------------------------------------------------------- /chapter6/README.md: -------------------------------------------------------------------------------- 1 | Netty Cookbook - chapter 6 code -------------------------------------------------------------------------------- /chapter6/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'java' 2 | apply plugin: 'eclipse' 3 | 4 | sourceCompatibility = 1.8 5 | 6 | version = '1.0' 7 | 8 | repositories { 9 | mavenCentral() 10 | } 11 | 12 | dependencies { 13 | compile ( 14 | // common 15 | 'io.netty:netty-all:4.0.25.Final' 16 | ,'commons-io:commons-io:2.4' 17 | ,'org.apache.commons:commons-lang3:3.3.2' 18 | ,'log4j:log4j:1.2.17' 19 | ,'org.slf4j:slf4j-log4j12:1.7.7' 20 | ,'org.yaml:snakeyaml:1.14' 21 | 22 | ,'com.google.code.gson:gson:2.3' 23 | ,'com.google.guava:guava:18.0' 24 | ,'org.twitter4j:twitter4j-core:4.0.2' 25 | ,'org.twitter4j:twitter4j-stream:4.0.2' 26 | ,'redis.clients:jedis:2.6.2' 27 | ,'com.github.jknack:handlebars:2.0.0' 28 | 29 | ) 30 | testCompile group: 'junit', name: 'junit', version: '4.11' 31 | } 32 | -------------------------------------------------------------------------------- /chapter6/src/main/java/chapter4/recipe1/WebSocketServer.java: -------------------------------------------------------------------------------- 1 | package chapter4.recipe1; 2 | 3 | 4 | /** 5 | * @author toddf 6 | * @since June 29, 2012 7 | */ 8 | public class WebSocketServer { 9 | 10 | 11 | public static void main(String[] args) { 12 | } 13 | } -------------------------------------------------------------------------------- /chapter6/src/main/java/chapter4/recipe2/RealtimeWebSocketIO.java: -------------------------------------------------------------------------------- 1 | package chapter4.recipe2; 2 | 3 | public class RealtimeWebSocketIO { 4 | 5 | } 6 | -------------------------------------------------------------------------------- /chapter6/src/main/java/chapter4/recipe3/ChatServerWithSTOMP.java: -------------------------------------------------------------------------------- 1 | package chapter4.recipe3; 2 | 3 | public class ChatServerWithSTOMP { 4 | 5 | } 6 | -------------------------------------------------------------------------------- /chapter6/src/main/java/chapter4/recipe4/RealtimeWidgetServer.java: -------------------------------------------------------------------------------- 1 | package chapter4.recipe4; 2 | 3 | public class RealtimeWidgetServer { 4 | 5 | } 6 | -------------------------------------------------------------------------------- /chapter6/src/main/java/log4j.properties: -------------------------------------------------------------------------------- 1 | # Root logger option 2 | log4j.rootLogger=INFO, stdout 3 | 4 | # Redirect log messages to console 5 | log4j.appender.stdout=org.apache.log4j.ConsoleAppender 6 | log4j.appender.stdout.Target=System.out 7 | log4j.appender.stdout.layout=org.apache.log4j.PatternLayout 8 | log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n 9 | 10 | # Redirect log messages to a log file, support file rolling. 11 | log4j.appender.file=org.apache.log4j.RollingFileAppender 12 | log4j.appender.file.File=./log/java-cookbook-demo 13 | log4j.appender.file.MaxFileSize=5MB 14 | log4j.appender.file.MaxBackupIndex=10 15 | log4j.appender.file.layout=org.apache.log4j.PatternLayout 16 | log4j.appender.file.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n -------------------------------------------------------------------------------- /chapter6/src/main/java/netty/cookbook/common/CallbackProcessor.java: -------------------------------------------------------------------------------- 1 | package netty.cookbook.common; 2 | 3 | @FunctionalInterface 4 | public interface CallbackProcessor { 5 | public void process(Object obj); 6 | } -------------------------------------------------------------------------------- /chapter6/src/main/java/netty/cookbook/common/CharPool.java: -------------------------------------------------------------------------------- 1 | package netty.cookbook.common; 2 | 3 | public class CharPool { 4 | 5 | public static final char AMPERSAND = '&'; 6 | 7 | public static final char APOSTROPHE = '\''; 8 | 9 | public static final char AT = '@'; 10 | 11 | public static final char BACK_SLASH = '\\'; 12 | 13 | public static final char CLOSE_BRACKET = ']'; 14 | 15 | public static final char CLOSE_CURLY_BRACE = '}'; 16 | 17 | public static final char CLOSE_PARENTHESIS = ')'; 18 | 19 | public static final char COLON = ':'; 20 | 21 | public static final char COMMA = ','; 22 | 23 | public static final char DASH = '-'; 24 | 25 | public static final char EQUAL = '='; 26 | 27 | public static final char GREATER_THAN = '>'; 28 | 29 | public static final char FORWARD_SLASH = '/'; 30 | 31 | public static final char LESS_THAN = '<'; 32 | 33 | public static final char LOWER_CASE_E = 'e'; 34 | 35 | public static final char MINUS = '-'; 36 | 37 | public static final char NEW_LINE = '\n'; 38 | 39 | public static final char OPEN_BRACKET = '['; 40 | 41 | public static final char OPEN_CURLY_BRACE = '{'; 42 | 43 | public static final char OPEN_PARENTHESIS = '('; 44 | 45 | public static final char PERCENT = '%'; 46 | 47 | public static final char PERIOD = '.'; 48 | 49 | public static final char PIPE = '|'; 50 | 51 | public static final char PLUS = '+'; 52 | 53 | public static final char POUND = '#'; 54 | 55 | public static final char QUESTION = '?'; 56 | 57 | public static final char QUOTE = '\"'; 58 | 59 | public static final char RETURN = '\r'; 60 | 61 | public static final char SEMICOLON = ';'; 62 | 63 | public static final char SLASH = FORWARD_SLASH; 64 | 65 | public static final char SPACE = ' '; 66 | 67 | public static final char STAR = '*'; 68 | 69 | public static final char TILDE = '~'; 70 | 71 | public static final char UNDERLINE = '_'; 72 | 73 | public static final char UPPER_CASE_E = 'E'; 74 | 75 | public static final char TAB = '\t'; 76 | 77 | } 78 | -------------------------------------------------------------------------------- /chapter6/src/main/java/netty/cookbook/common/LogUtil.java: -------------------------------------------------------------------------------- 1 | package netty.cookbook.common; 2 | 3 | public class LogUtil { 4 | 5 | public static void println(Object obj){ 6 | System.out.println(obj); 7 | } 8 | 9 | public static void println(String obj){ 10 | System.out.println(obj); 11 | } 12 | 13 | 14 | } 15 | -------------------------------------------------------------------------------- /chapter6/src/main/java/netty/cookbook/common/TcpChannelHandler.java: -------------------------------------------------------------------------------- 1 | package netty.cookbook.common; 2 | 3 | import io.netty.channel.ChannelHandlerContext; 4 | 5 | @FunctionalInterface 6 | public interface TcpChannelHandler { 7 | public void process(ChannelHandlerContext ctx, Object msg); 8 | } 9 | -------------------------------------------------------------------------------- /chapter6/src/main/java/netty/cookbook/common/UrlUtil.java: -------------------------------------------------------------------------------- 1 | package netty.cookbook.common; 2 | 3 | import java.net.MalformedURLException; 4 | import java.net.URL; 5 | 6 | public class UrlUtil { 7 | public final static String REGEX_FOR_ROOT_DOMAIN = ".*\\.(?=.*\\.)"; 8 | 9 | public static String getRootDomain(String fullUrl) throws MalformedURLException{ 10 | return new URL(fullUrl).getHost().replaceAll(REGEX_FOR_ROOT_DOMAIN, ""); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /chapter6/src/main/java/netty/cookbook/common/http/ContentTypePool.java: -------------------------------------------------------------------------------- 1 | package netty.cookbook.common.http; 2 | 3 | public class ContentTypePool { 4 | public static final String GIF = "image/gif"; 5 | public static final String TRACKING_GIF = GIF; 6 | public static final String JPEG = "image/jpeg"; 7 | 8 | public static final String JAVA_SCRIPT = "application/javascript; charset=utf-8"; 9 | public static final String XML = "application/xml; charset=utf-8"; 10 | public static final String JSON = "application/json; charset=utf-8"; 11 | 12 | public static final String TEXT_UTF8 = "text/plain; charset=UTF-8"; 13 | public static final String HTML_UTF8 = "text/html; charset=UTF-8"; 14 | } 15 | -------------------------------------------------------------------------------- /chapter6/src/main/java/netty/cookbook/common/http/HttpOutputResource.java: -------------------------------------------------------------------------------- 1 | package netty.cookbook.common.http; 2 | 3 | import io.netty.buffer.ByteBuf; 4 | 5 | public class HttpOutputResource { 6 | ByteBuf byteBuf; 7 | long length; 8 | long lastModified; 9 | 10 | 11 | public HttpOutputResource(ByteBuf byteBuf, long lastModified) { 12 | super(); 13 | this.byteBuf = byteBuf; 14 | this.length = byteBuf.readableBytes(); 15 | this.lastModified = lastModified; 16 | } 17 | 18 | public ByteBuf getByteBuf() { 19 | return byteBuf; 20 | } 21 | 22 | public void setByteBuf(ByteBuf byteBuf) { 23 | this.byteBuf = byteBuf; 24 | } 25 | 26 | public long getLength() { 27 | return length; 28 | } 29 | 30 | public void setLength(long length) { 31 | this.length = length; 32 | } 33 | 34 | public long getLastModified() { 35 | return lastModified; 36 | } 37 | 38 | public void setLastModified(long lastModified) { 39 | this.lastModified = lastModified; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /chapter6/src/main/java/netty/cookbook/common/redis/RedisCommand.java: -------------------------------------------------------------------------------- 1 | package netty.cookbook.common.redis; 2 | 3 | import netty.cookbook.common.StringPool; 4 | import redis.clients.jedis.Jedis; 5 | import redis.clients.jedis.ShardedJedis; 6 | import redis.clients.jedis.ShardedJedisPool; 7 | import redis.clients.jedis.exceptions.JedisException; 8 | 9 | public abstract class RedisCommand { 10 | protected ShardedJedisPool jedisPool; 11 | protected ShardedJedis shardedJedis = null; 12 | protected Jedis jedis = null; 13 | 14 | public RedisCommand(ShardedJedisPool jedisPool) { 15 | super(); 16 | if (jedisPool == null) { 17 | throw new IllegalArgumentException("jedisPool is NULL!"); 18 | } 19 | this.jedisPool = jedisPool; 20 | } 21 | 22 | public T execute() { 23 | boolean commited = false; 24 | T rs = null; 25 | try { 26 | shardedJedis = jedisPool.getResource(); 27 | if (shardedJedis != null) { 28 | jedis = shardedJedis.getShard(StringPool.BLANK); 29 | rs = build(); 30 | commited = true; 31 | } 32 | } catch (Exception e) { 33 | e.printStackTrace(); 34 | } finally { 35 | freeRedisResource(jedisPool, shardedJedis, commited); 36 | } 37 | return rs; 38 | } 39 | 40 | public static void freeRedisResource(ShardedJedisPool jedisPool, ShardedJedis shardedJedis, boolean isCommited){ 41 | if (shardedJedis != null && jedisPool != null) { 42 | if (isCommited) { 43 | jedisPool.returnResource(shardedJedis); 44 | } else { 45 | jedisPool.returnBrokenResource(shardedJedis); 46 | } 47 | } 48 | } 49 | 50 | //define the logic at implementer 51 | protected abstract T build() throws JedisException; 52 | } -------------------------------------------------------------------------------- /chapter6/src/main/java/netty/cookbook/common/redis/RedisInfo.java: -------------------------------------------------------------------------------- 1 | package netty.cookbook.common.redis; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | import redis.clients.jedis.JedisShardInfo; 7 | import redis.clients.jedis.ShardedJedisPool; 8 | 9 | public class RedisInfo { 10 | public static final String LOCALHOST_STR = "localhost"; 11 | 12 | private String host; 13 | private int port; 14 | private String auth; 15 | private ShardedJedisPool shardedJedisPool; 16 | 17 | protected void initThePool(){ 18 | List shardInfos = new ArrayList(1); 19 | shardInfos.add(new JedisShardInfo(getHost(), getPort(), 0)); 20 | shardedJedisPool = new ShardedJedisPool(RedisConnectionPoolConfig.getJedisPoolConfigInstance(), shardInfos); 21 | } 22 | 23 | public RedisInfo(String host, int port) { 24 | this.host = host; 25 | this.port = port; 26 | initThePool(); 27 | } 28 | 29 | public RedisInfo(String host, int port,String auth) { 30 | this.host = host; 31 | this.port = port; 32 | this.auth = auth; 33 | initThePool(); 34 | } 35 | 36 | public String getHost() { 37 | return host; 38 | } 39 | 40 | public int getPort() { 41 | return port; 42 | } 43 | 44 | public String getAuth() { 45 | return auth; 46 | } 47 | 48 | @Override 49 | public boolean equals(Object obj) { 50 | if (obj instanceof RedisInfo) { 51 | RedisInfo hp = (RedisInfo) obj; 52 | 53 | String thisHost = convertHost(host); 54 | String hpHost = convertHost(hp.host); 55 | return port == hp.port && thisHost.equals(hpHost); 56 | 57 | } 58 | 59 | return false; 60 | } 61 | 62 | public ShardedJedisPool getShardedJedisPool() { 63 | return shardedJedisPool; 64 | } 65 | 66 | @Override 67 | public String toString() { 68 | return host + ":" + port; 69 | } 70 | 71 | private String convertHost(String host) { 72 | if (host.equals("127.0.0.1")) 73 | return LOCALHOST_STR; 74 | else if (host.equals("::1")) 75 | return LOCALHOST_STR; 76 | 77 | return host; 78 | } 79 | } -------------------------------------------------------------------------------- /chapter7/.gitignore: -------------------------------------------------------------------------------- 1 | /bin/ 2 | /build/ 3 | -------------------------------------------------------------------------------- /chapter7/.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | chapter7 4 | 5 | 6 | 7 | 8 | 9 | org.eclipse.jdt.core.javabuilder 10 | 11 | 12 | 13 | 14 | 15 | org.springsource.ide.eclipse.gradle.core.nature 16 | org.eclipse.jdt.core.javanature 17 | 18 | 19 | -------------------------------------------------------------------------------- /chapter7/README.md: -------------------------------------------------------------------------------- 1 | ![Alt text](http://www.tech-wd.com/wd/wp-content/uploads/2015/02/http_2.gif) 2 | 3 | Netty Cookbook - code for chapter 7: High performance Web with HTTP/2 4 | 5 | https://http2.github.io 6 | http://en.wikipedia.org/wiki/HTTP/2 7 | 8 | * Recipe 7.1 Using codec-http2 to improve the speed of Web 9 | * Recipe 7.2 Enabling multiple streams in single connection 10 | * Recipe 7.3 Setting priority in requests 11 | * Recipe 7.4 Compressing data response 12 | * Recipe 7.5 Enabling server push 13 | * Recipe 7.6 Building better static file server for high concurrency 14 | -------------------------------------------------------------------------------- /chapter7/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'java' 2 | apply plugin: 'eclipse' 3 | 4 | sourceCompatibility = 1.8 5 | 6 | version = '1.0' 7 | 8 | repositories { 9 | mavenCentral() 10 | maven { 11 | url "http://clinker.netty.io/nexus/content/repositories/snapshots/" 12 | } 13 | } 14 | 15 | dependencies { 16 | compile ( 17 | // common 18 | 'io.netty:netty-all:5.0.0.Alpha2-SNAPSHOT' 19 | ,'com.twitter:hpack:0.10.0' 20 | 21 | ,'commons-io:commons-io:2.4' 22 | ,'org.apache.commons:commons-lang3:3.3.2' 23 | ,'log4j:log4j:1.2.17' 24 | ,'org.slf4j:slf4j-log4j12:1.7.7' 25 | ,'org.yaml:snakeyaml:1.14' 26 | 27 | ,'com.google.code.gson:gson:2.3' 28 | ,'com.google.guava:guava:18.0' 29 | ,'org.twitter4j:twitter4j-core:4.0.2' 30 | ,'org.twitter4j:twitter4j-stream:4.0.2' 31 | ,'redis.clients:jedis:2.6.2' 32 | ,'com.github.jknack:handlebars:2.0.0' 33 | 34 | ) 35 | testCompile group: 'junit', name: 'junit', version: '4.11' 36 | } 37 | -------------------------------------------------------------------------------- /chapter7/src/main/java/chapter7/recipe1/client/Http2SettingsHandler.java: -------------------------------------------------------------------------------- 1 | package chapter7.recipe1.client; 2 | 3 | import io.netty.channel.ChannelHandlerContext; 4 | import io.netty.channel.ChannelPromise; 5 | import io.netty.channel.SimpleChannelInboundHandler; 6 | import io.netty.handler.codec.http2.Http2Settings; 7 | 8 | import java.util.concurrent.TimeUnit; 9 | 10 | /** 11 | * Reads the first {@link Http2Settings} object and notifies a {@link ChannelPromise} 12 | */ 13 | public class Http2SettingsHandler extends SimpleChannelInboundHandler { 14 | private ChannelPromise promise; 15 | 16 | /** 17 | * Create new instance 18 | * 19 | * @param promise Promise object used to notify when first settings are received 20 | */ 21 | public Http2SettingsHandler(ChannelPromise promise) { 22 | this.promise = promise; 23 | } 24 | 25 | /** 26 | * Wait for this handler to be added after the upgrade to HTTP/2, and for initial preface 27 | * handshake to complete. 28 | * 29 | * @param timeout Time to wait 30 | * @param unit {@link TimeUnit} for {@code timeout} 31 | * @throws Exception if timeout or other failure occurs 32 | */ 33 | public void awaitSettings(long timeout, TimeUnit unit) throws Exception { 34 | if (!promise.awaitUninterruptibly(timeout, unit)) { 35 | throw new IllegalStateException("Timed out waiting for settings"); 36 | } 37 | if (!promise.isSuccess()) { 38 | throw new RuntimeException(promise.cause()); 39 | } 40 | } 41 | 42 | @Override 43 | protected void messageReceived(ChannelHandlerContext ctx, Http2Settings msg) throws Exception { 44 | promise.setSuccess(); 45 | 46 | // Only care about the first settings message 47 | ctx.pipeline().remove(this); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /chapter7/src/main/java/chapter7/recipe1/server/Http2OrHttpHandler.java: -------------------------------------------------------------------------------- 1 | package chapter7.recipe1.server; 2 | 3 | import io.netty.channel.ChannelHandler; 4 | import io.netty.handler.codec.http2.Http2ConnectionHandler; 5 | import io.netty.handler.codec.http2.Http2OrHttpChooser; 6 | 7 | import javax.net.ssl.SSLEngine; 8 | 9 | /** 10 | * Negotiates with the browser if HTTP2 or HTTP is going to be used. Once decided, the Netty 11 | * pipeline is setup with the correct handlers for the selected protocol. 12 | */ 13 | public class Http2OrHttpHandler extends Http2OrHttpChooser { 14 | private static final int MAX_CONTENT_LENGTH = 1024 * 100; 15 | 16 | public Http2OrHttpHandler() { 17 | this(MAX_CONTENT_LENGTH); 18 | } 19 | 20 | public Http2OrHttpHandler(int maxHttpContentLength) { 21 | super(maxHttpContentLength); 22 | } 23 | 24 | @Override 25 | protected SelectedProtocol getProtocol(SSLEngine engine) { 26 | String[] protocol = engine.getSession().getProtocol().split(":"); 27 | if (protocol != null && protocol.length > 1) { 28 | SelectedProtocol selectedProtocol = SelectedProtocol.protocol(protocol[1]); 29 | System.err.println("Selected Protocol is " + selectedProtocol); 30 | return selectedProtocol; 31 | } 32 | return SelectedProtocol.UNKNOWN; 33 | } 34 | 35 | @Override 36 | protected ChannelHandler createHttp1RequestHandler() { 37 | return new HelloWorldHttp1Handler(); 38 | } 39 | 40 | @Override 41 | protected Http2ConnectionHandler createHttp2RequestHandler() { 42 | return new HelloWorldHttp2Handler(); 43 | } 44 | 45 | } 46 | -------------------------------------------------------------------------------- /chapter7/src/main/java/chapter7/recipe1/server/Http2Server.java: -------------------------------------------------------------------------------- 1 | package chapter7.recipe1.server; 2 | 3 | import io.netty.bootstrap.ServerBootstrap; 4 | import io.netty.channel.Channel; 5 | import io.netty.channel.ChannelOption; 6 | import io.netty.channel.EventLoopGroup; 7 | import io.netty.channel.nio.NioEventLoopGroup; 8 | import io.netty.channel.socket.nio.NioServerSocketChannel; 9 | import io.netty.handler.logging.LogLevel; 10 | import io.netty.handler.logging.LoggingHandler; 11 | 12 | /** 13 | * @author Trieu 14 | * @since Feb 23, 2015 15 | */ 16 | public class Http2Server { 17 | 18 | static final boolean SSL = System.getProperty("ssl") != null; 19 | static final int PORT = Integer.parseInt(System.getProperty("port", SSL? "8443" : "8080")); 20 | 21 | public static void main(String[] args) throws Exception { 22 | 23 | // Configure the server. 24 | EventLoopGroup bossGroup = new NioEventLoopGroup(1); 25 | EventLoopGroup workerGroup = new NioEventLoopGroup(); 26 | try { 27 | ServerBootstrap b = new ServerBootstrap(); 28 | b.option(ChannelOption.SO_BACKLOG, 1024); 29 | b.group(bossGroup, workerGroup) 30 | .channel(NioServerSocketChannel.class) 31 | .handler(new LoggingHandler(LogLevel.INFO)) 32 | .childHandler(new Http2ServerInitializer()); 33 | 34 | Channel ch = b.bind(PORT).sync().channel(); 35 | 36 | System.err.println("Open your HTTP/2-enabled web browser and navigate to " + 37 | (SSL? "https" : "http") + "://127.0.0.1:" + PORT + '/'); 38 | 39 | ch.closeFuture().sync(); 40 | } finally { 41 | bossGroup.shutdownGracefully(); 42 | workerGroup.shutdownGracefully(); 43 | } 44 | } 45 | } -------------------------------------------------------------------------------- /chapter7/src/main/java/log4j.properties: -------------------------------------------------------------------------------- 1 | # Root logger option 2 | log4j.rootLogger=INFO, stdout 3 | 4 | # Redirect log messages to console 5 | log4j.appender.stdout=org.apache.log4j.ConsoleAppender 6 | log4j.appender.stdout.Target=System.out 7 | log4j.appender.stdout.layout=org.apache.log4j.PatternLayout 8 | log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n 9 | 10 | # Redirect log messages to a log file, support file rolling. 11 | log4j.appender.file=org.apache.log4j.RollingFileAppender 12 | log4j.appender.file.File=./log/java-cookbook-demo 13 | log4j.appender.file.MaxFileSize=5MB 14 | log4j.appender.file.MaxBackupIndex=10 15 | log4j.appender.file.layout=org.apache.log4j.PatternLayout 16 | log4j.appender.file.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n -------------------------------------------------------------------------------- /chapter7/src/main/java/netty/cookbook/common/CallbackProcessor.java: -------------------------------------------------------------------------------- 1 | package netty.cookbook.common; 2 | 3 | @FunctionalInterface 4 | public interface CallbackProcessor { 5 | public void process(Object obj); 6 | } -------------------------------------------------------------------------------- /chapter7/src/main/java/netty/cookbook/common/CharPool.java: -------------------------------------------------------------------------------- 1 | package netty.cookbook.common; 2 | 3 | public class CharPool { 4 | 5 | public static final char AMPERSAND = '&'; 6 | 7 | public static final char APOSTROPHE = '\''; 8 | 9 | public static final char AT = '@'; 10 | 11 | public static final char BACK_SLASH = '\\'; 12 | 13 | public static final char CLOSE_BRACKET = ']'; 14 | 15 | public static final char CLOSE_CURLY_BRACE = '}'; 16 | 17 | public static final char CLOSE_PARENTHESIS = ')'; 18 | 19 | public static final char COLON = ':'; 20 | 21 | public static final char COMMA = ','; 22 | 23 | public static final char DASH = '-'; 24 | 25 | public static final char EQUAL = '='; 26 | 27 | public static final char GREATER_THAN = '>'; 28 | 29 | public static final char FORWARD_SLASH = '/'; 30 | 31 | public static final char LESS_THAN = '<'; 32 | 33 | public static final char LOWER_CASE_E = 'e'; 34 | 35 | public static final char MINUS = '-'; 36 | 37 | public static final char NEW_LINE = '\n'; 38 | 39 | public static final char OPEN_BRACKET = '['; 40 | 41 | public static final char OPEN_CURLY_BRACE = '{'; 42 | 43 | public static final char OPEN_PARENTHESIS = '('; 44 | 45 | public static final char PERCENT = '%'; 46 | 47 | public static final char PERIOD = '.'; 48 | 49 | public static final char PIPE = '|'; 50 | 51 | public static final char PLUS = '+'; 52 | 53 | public static final char POUND = '#'; 54 | 55 | public static final char QUESTION = '?'; 56 | 57 | public static final char QUOTE = '\"'; 58 | 59 | public static final char RETURN = '\r'; 60 | 61 | public static final char SEMICOLON = ';'; 62 | 63 | public static final char SLASH = FORWARD_SLASH; 64 | 65 | public static final char SPACE = ' '; 66 | 67 | public static final char STAR = '*'; 68 | 69 | public static final char TILDE = '~'; 70 | 71 | public static final char UNDERLINE = '_'; 72 | 73 | public static final char UPPER_CASE_E = 'E'; 74 | 75 | public static final char TAB = '\t'; 76 | 77 | } 78 | -------------------------------------------------------------------------------- /chapter7/src/main/java/netty/cookbook/common/Http2Util.java: -------------------------------------------------------------------------------- 1 | package netty.cookbook.common; 2 | 3 | public class Http2Util { 4 | /** 5 | * Response header sent in response to the http->http2 cleartext upgrade request. 6 | */ 7 | public static final String UPGRADE_RESPONSE_HEADER = "Http-To-Http2-Upgrade"; 8 | } 9 | -------------------------------------------------------------------------------- /chapter7/src/main/java/netty/cookbook/common/LogUtil.java: -------------------------------------------------------------------------------- 1 | package netty.cookbook.common; 2 | 3 | public class LogUtil { 4 | 5 | public static void println(Object obj){ 6 | System.out.println(obj); 7 | } 8 | 9 | public static void println(String obj){ 10 | System.out.println(obj); 11 | } 12 | 13 | 14 | } 15 | -------------------------------------------------------------------------------- /chapter7/src/main/java/netty/cookbook/common/UrlUtil.java: -------------------------------------------------------------------------------- 1 | package netty.cookbook.common; 2 | 3 | import java.net.MalformedURLException; 4 | import java.net.URL; 5 | 6 | public class UrlUtil { 7 | public final static String REGEX_FOR_ROOT_DOMAIN = ".*\\.(?=.*\\.)"; 8 | 9 | public static String getRootDomain(String fullUrl) throws MalformedURLException{ 10 | return new URL(fullUrl).getHost().replaceAll(REGEX_FOR_ROOT_DOMAIN, ""); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /chapter7/src/main/java/netty/cookbook/common/redis/RedisCommand.java: -------------------------------------------------------------------------------- 1 | package netty.cookbook.common.redis; 2 | 3 | import netty.cookbook.common.StringPool; 4 | import redis.clients.jedis.Jedis; 5 | import redis.clients.jedis.ShardedJedis; 6 | import redis.clients.jedis.ShardedJedisPool; 7 | import redis.clients.jedis.exceptions.JedisException; 8 | 9 | public abstract class RedisCommand { 10 | protected ShardedJedisPool jedisPool; 11 | protected ShardedJedis shardedJedis = null; 12 | protected Jedis jedis = null; 13 | 14 | public RedisCommand(ShardedJedisPool jedisPool) { 15 | super(); 16 | if (jedisPool == null) { 17 | throw new IllegalArgumentException("jedisPool is NULL!"); 18 | } 19 | this.jedisPool = jedisPool; 20 | } 21 | 22 | public T execute() { 23 | boolean commited = false; 24 | T rs = null; 25 | try { 26 | shardedJedis = jedisPool.getResource(); 27 | if (shardedJedis != null) { 28 | jedis = shardedJedis.getShard(StringPool.BLANK); 29 | rs = build(); 30 | commited = true; 31 | } 32 | } catch (Exception e) { 33 | e.printStackTrace(); 34 | } finally { 35 | freeRedisResource(jedisPool, shardedJedis, commited); 36 | } 37 | return rs; 38 | } 39 | 40 | public static void freeRedisResource(ShardedJedisPool jedisPool, ShardedJedis shardedJedis, boolean isCommited){ 41 | if (shardedJedis != null && jedisPool != null) { 42 | if (isCommited) { 43 | jedisPool.returnResource(shardedJedis); 44 | } else { 45 | jedisPool.returnBrokenResource(shardedJedis); 46 | } 47 | } 48 | } 49 | 50 | //define the logic at implementer 51 | protected abstract T build() throws JedisException; 52 | } -------------------------------------------------------------------------------- /chapter7/src/main/java/netty/cookbook/common/redis/RedisInfo.java: -------------------------------------------------------------------------------- 1 | package netty.cookbook.common.redis; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | import redis.clients.jedis.JedisShardInfo; 7 | import redis.clients.jedis.ShardedJedisPool; 8 | 9 | public class RedisInfo { 10 | public static final String LOCALHOST_STR = "localhost"; 11 | 12 | private String host; 13 | private int port; 14 | private String auth; 15 | private ShardedJedisPool shardedJedisPool; 16 | 17 | protected void initThePool(){ 18 | List shardInfos = new ArrayList(1); 19 | shardInfos.add(new JedisShardInfo(getHost(), getPort(), 0)); 20 | shardedJedisPool = new ShardedJedisPool(RedisConnectionPoolConfig.getJedisPoolConfigInstance(), shardInfos); 21 | } 22 | 23 | public RedisInfo(String host, int port) { 24 | this.host = host; 25 | this.port = port; 26 | initThePool(); 27 | } 28 | 29 | public RedisInfo(String host, int port,String auth) { 30 | this.host = host; 31 | this.port = port; 32 | this.auth = auth; 33 | initThePool(); 34 | } 35 | 36 | public String getHost() { 37 | return host; 38 | } 39 | 40 | public int getPort() { 41 | return port; 42 | } 43 | 44 | public String getAuth() { 45 | return auth; 46 | } 47 | 48 | @Override 49 | public boolean equals(Object obj) { 50 | if (obj instanceof RedisInfo) { 51 | RedisInfo hp = (RedisInfo) obj; 52 | 53 | String thisHost = convertHost(host); 54 | String hpHost = convertHost(hp.host); 55 | return port == hp.port && thisHost.equals(hpHost); 56 | 57 | } 58 | 59 | return false; 60 | } 61 | 62 | public ShardedJedisPool getShardedJedisPool() { 63 | return shardedJedisPool; 64 | } 65 | 66 | @Override 67 | public String toString() { 68 | return host + ":" + port; 69 | } 70 | 71 | private String convertHost(String host) { 72 | if (host.equals("127.0.0.1")) 73 | return LOCALHOST_STR; 74 | else if (host.equals("::1")) 75 | return LOCALHOST_STR; 76 | 77 | return host; 78 | } 79 | } -------------------------------------------------------------------------------- /chapter8/.gitignore: -------------------------------------------------------------------------------- 1 | /bin/ 2 | /build/ 3 | -------------------------------------------------------------------------------- /chapter8/.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | chapter5 4 | 5 | 6 | 7 | 8 | 9 | org.eclipse.jdt.core.javabuilder 10 | 11 | 12 | 13 | 14 | 15 | org.springsource.ide.eclipse.gradle.core.nature 16 | org.eclipse.jdt.core.javanature 17 | 18 | 19 | -------------------------------------------------------------------------------- /chapter8/README.md: -------------------------------------------------------------------------------- 1 | Netty Cookbook - chapter 8 code -------------------------------------------------------------------------------- /chapter8/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'java' 2 | apply plugin: 'eclipse' 3 | 4 | sourceCompatibility = 1.8 5 | 6 | version = '1.0' 7 | 8 | repositories { 9 | mavenCentral() 10 | } 11 | 12 | dependencies { 13 | compile ( 14 | // common 15 | 'io.netty:netty-all:4.0.25.Final' 16 | ,'commons-io:commons-io:2.4' 17 | ,'org.apache.commons:commons-lang3:3.3.2' 18 | ,'log4j:log4j:1.2.17' 19 | ,'org.slf4j:slf4j-log4j12:1.7.7' 20 | ,'org.yaml:snakeyaml:1.14' 21 | 22 | ,'com.google.code.gson:gson:2.3' 23 | ,'com.google.guava:guava:18.0' 24 | ,'org.twitter4j:twitter4j-core:4.0.2' 25 | ,'org.twitter4j:twitter4j-stream:4.0.2' 26 | ,'redis.clients:jedis:2.6.2' 27 | ,'com.github.jknack:handlebars:2.0.0' 28 | 29 | ) 30 | testCompile group: 'junit', name: 'junit', version: '4.11' 31 | } 32 | -------------------------------------------------------------------------------- /chapter8/src/main/java/chapter4/recipe1/WebSocketServer.java: -------------------------------------------------------------------------------- 1 | package chapter4.recipe1; 2 | 3 | 4 | /** 5 | * @author toddf 6 | * @since June 29, 2012 7 | */ 8 | public class WebSocketServer { 9 | 10 | 11 | public static void main(String[] args) { 12 | } 13 | } -------------------------------------------------------------------------------- /chapter8/src/main/java/chapter4/recipe2/RealtimeWebSocketIO.java: -------------------------------------------------------------------------------- 1 | package chapter4.recipe2; 2 | 3 | public class RealtimeWebSocketIO { 4 | 5 | } 6 | -------------------------------------------------------------------------------- /chapter8/src/main/java/chapter4/recipe3/ChatServerWithSTOMP.java: -------------------------------------------------------------------------------- 1 | package chapter4.recipe3; 2 | 3 | public class ChatServerWithSTOMP { 4 | 5 | } 6 | -------------------------------------------------------------------------------- /chapter8/src/main/java/chapter4/recipe4/RealtimeWidgetServer.java: -------------------------------------------------------------------------------- 1 | package chapter4.recipe4; 2 | 3 | public class RealtimeWidgetServer { 4 | 5 | } 6 | -------------------------------------------------------------------------------- /chapter8/src/main/java/log4j.properties: -------------------------------------------------------------------------------- 1 | # Root logger option 2 | log4j.rootLogger=INFO, stdout 3 | 4 | # Redirect log messages to console 5 | log4j.appender.stdout=org.apache.log4j.ConsoleAppender 6 | log4j.appender.stdout.Target=System.out 7 | log4j.appender.stdout.layout=org.apache.log4j.PatternLayout 8 | log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n 9 | 10 | # Redirect log messages to a log file, support file rolling. 11 | log4j.appender.file=org.apache.log4j.RollingFileAppender 12 | log4j.appender.file.File=./log/java-cookbook-demo 13 | log4j.appender.file.MaxFileSize=5MB 14 | log4j.appender.file.MaxBackupIndex=10 15 | log4j.appender.file.layout=org.apache.log4j.PatternLayout 16 | log4j.appender.file.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n -------------------------------------------------------------------------------- /chapter8/src/main/java/netty/cookbook/common/CallbackProcessor.java: -------------------------------------------------------------------------------- 1 | package netty.cookbook.common; 2 | 3 | @FunctionalInterface 4 | public interface CallbackProcessor { 5 | public void process(Object obj); 6 | } -------------------------------------------------------------------------------- /chapter8/src/main/java/netty/cookbook/common/CharPool.java: -------------------------------------------------------------------------------- 1 | package netty.cookbook.common; 2 | 3 | public class CharPool { 4 | 5 | public static final char AMPERSAND = '&'; 6 | 7 | public static final char APOSTROPHE = '\''; 8 | 9 | public static final char AT = '@'; 10 | 11 | public static final char BACK_SLASH = '\\'; 12 | 13 | public static final char CLOSE_BRACKET = ']'; 14 | 15 | public static final char CLOSE_CURLY_BRACE = '}'; 16 | 17 | public static final char CLOSE_PARENTHESIS = ')'; 18 | 19 | public static final char COLON = ':'; 20 | 21 | public static final char COMMA = ','; 22 | 23 | public static final char DASH = '-'; 24 | 25 | public static final char EQUAL = '='; 26 | 27 | public static final char GREATER_THAN = '>'; 28 | 29 | public static final char FORWARD_SLASH = '/'; 30 | 31 | public static final char LESS_THAN = '<'; 32 | 33 | public static final char LOWER_CASE_E = 'e'; 34 | 35 | public static final char MINUS = '-'; 36 | 37 | public static final char NEW_LINE = '\n'; 38 | 39 | public static final char OPEN_BRACKET = '['; 40 | 41 | public static final char OPEN_CURLY_BRACE = '{'; 42 | 43 | public static final char OPEN_PARENTHESIS = '('; 44 | 45 | public static final char PERCENT = '%'; 46 | 47 | public static final char PERIOD = '.'; 48 | 49 | public static final char PIPE = '|'; 50 | 51 | public static final char PLUS = '+'; 52 | 53 | public static final char POUND = '#'; 54 | 55 | public static final char QUESTION = '?'; 56 | 57 | public static final char QUOTE = '\"'; 58 | 59 | public static final char RETURN = '\r'; 60 | 61 | public static final char SEMICOLON = ';'; 62 | 63 | public static final char SLASH = FORWARD_SLASH; 64 | 65 | public static final char SPACE = ' '; 66 | 67 | public static final char STAR = '*'; 68 | 69 | public static final char TILDE = '~'; 70 | 71 | public static final char UNDERLINE = '_'; 72 | 73 | public static final char UPPER_CASE_E = 'E'; 74 | 75 | public static final char TAB = '\t'; 76 | 77 | } 78 | -------------------------------------------------------------------------------- /chapter8/src/main/java/netty/cookbook/common/LogUtil.java: -------------------------------------------------------------------------------- 1 | package netty.cookbook.common; 2 | 3 | public class LogUtil { 4 | 5 | public static void println(Object obj){ 6 | System.out.println(obj); 7 | } 8 | 9 | public static void println(String obj){ 10 | System.out.println(obj); 11 | } 12 | 13 | 14 | } 15 | -------------------------------------------------------------------------------- /chapter8/src/main/java/netty/cookbook/common/TcpChannelHandler.java: -------------------------------------------------------------------------------- 1 | package netty.cookbook.common; 2 | 3 | import io.netty.channel.ChannelHandlerContext; 4 | 5 | @FunctionalInterface 6 | public interface TcpChannelHandler { 7 | public void process(ChannelHandlerContext ctx, Object msg); 8 | } 9 | -------------------------------------------------------------------------------- /chapter8/src/main/java/netty/cookbook/common/UrlUtil.java: -------------------------------------------------------------------------------- 1 | package netty.cookbook.common; 2 | 3 | import java.net.MalformedURLException; 4 | import java.net.URL; 5 | 6 | public class UrlUtil { 7 | public final static String REGEX_FOR_ROOT_DOMAIN = ".*\\.(?=.*\\.)"; 8 | 9 | public static String getRootDomain(String fullUrl) throws MalformedURLException{ 10 | return new URL(fullUrl).getHost().replaceAll(REGEX_FOR_ROOT_DOMAIN, ""); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /chapter8/src/main/java/netty/cookbook/common/http/ContentTypePool.java: -------------------------------------------------------------------------------- 1 | package netty.cookbook.common.http; 2 | 3 | public class ContentTypePool { 4 | public static final String GIF = "image/gif"; 5 | public static final String TRACKING_GIF = GIF; 6 | public static final String JPEG = "image/jpeg"; 7 | 8 | public static final String JAVA_SCRIPT = "application/javascript; charset=utf-8"; 9 | public static final String XML = "application/xml; charset=utf-8"; 10 | public static final String JSON = "application/json; charset=utf-8"; 11 | 12 | public static final String TEXT_UTF8 = "text/plain; charset=UTF-8"; 13 | public static final String HTML_UTF8 = "text/html; charset=UTF-8"; 14 | } 15 | -------------------------------------------------------------------------------- /chapter8/src/main/java/netty/cookbook/common/http/HttpOutputResource.java: -------------------------------------------------------------------------------- 1 | package netty.cookbook.common.http; 2 | 3 | import io.netty.buffer.ByteBuf; 4 | 5 | public class HttpOutputResource { 6 | ByteBuf byteBuf; 7 | long length; 8 | long lastModified; 9 | 10 | 11 | public HttpOutputResource(ByteBuf byteBuf, long lastModified) { 12 | super(); 13 | this.byteBuf = byteBuf; 14 | this.length = byteBuf.readableBytes(); 15 | this.lastModified = lastModified; 16 | } 17 | 18 | public ByteBuf getByteBuf() { 19 | return byteBuf; 20 | } 21 | 22 | public void setByteBuf(ByteBuf byteBuf) { 23 | this.byteBuf = byteBuf; 24 | } 25 | 26 | public long getLength() { 27 | return length; 28 | } 29 | 30 | public void setLength(long length) { 31 | this.length = length; 32 | } 33 | 34 | public long getLastModified() { 35 | return lastModified; 36 | } 37 | 38 | public void setLastModified(long lastModified) { 39 | this.lastModified = lastModified; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /chapter8/src/main/java/netty/cookbook/common/redis/RedisCommand.java: -------------------------------------------------------------------------------- 1 | package netty.cookbook.common.redis; 2 | 3 | import netty.cookbook.common.StringPool; 4 | import redis.clients.jedis.Jedis; 5 | import redis.clients.jedis.ShardedJedis; 6 | import redis.clients.jedis.ShardedJedisPool; 7 | import redis.clients.jedis.exceptions.JedisException; 8 | 9 | public abstract class RedisCommand { 10 | protected ShardedJedisPool jedisPool; 11 | protected ShardedJedis shardedJedis = null; 12 | protected Jedis jedis = null; 13 | 14 | public RedisCommand(ShardedJedisPool jedisPool) { 15 | super(); 16 | if (jedisPool == null) { 17 | throw new IllegalArgumentException("jedisPool is NULL!"); 18 | } 19 | this.jedisPool = jedisPool; 20 | } 21 | 22 | public T execute() { 23 | boolean commited = false; 24 | T rs = null; 25 | try { 26 | shardedJedis = jedisPool.getResource(); 27 | if (shardedJedis != null) { 28 | jedis = shardedJedis.getShard(StringPool.BLANK); 29 | rs = build(); 30 | commited = true; 31 | } 32 | } catch (Exception e) { 33 | e.printStackTrace(); 34 | } finally { 35 | freeRedisResource(jedisPool, shardedJedis, commited); 36 | } 37 | return rs; 38 | } 39 | 40 | public static void freeRedisResource(ShardedJedisPool jedisPool, ShardedJedis shardedJedis, boolean isCommited){ 41 | if (shardedJedis != null && jedisPool != null) { 42 | if (isCommited) { 43 | jedisPool.returnResource(shardedJedis); 44 | } else { 45 | jedisPool.returnBrokenResource(shardedJedis); 46 | } 47 | } 48 | } 49 | 50 | //define the logic at implementer 51 | protected abstract T build() throws JedisException; 52 | } -------------------------------------------------------------------------------- /chapter8/src/main/java/netty/cookbook/common/redis/RedisInfo.java: -------------------------------------------------------------------------------- 1 | package netty.cookbook.common.redis; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | import redis.clients.jedis.JedisShardInfo; 7 | import redis.clients.jedis.ShardedJedisPool; 8 | 9 | public class RedisInfo { 10 | public static final String LOCALHOST_STR = "localhost"; 11 | 12 | private String host; 13 | private int port; 14 | private String auth; 15 | private ShardedJedisPool shardedJedisPool; 16 | 17 | protected void initThePool(){ 18 | List shardInfos = new ArrayList(1); 19 | shardInfos.add(new JedisShardInfo(getHost(), getPort(), 0)); 20 | shardedJedisPool = new ShardedJedisPool(RedisConnectionPoolConfig.getJedisPoolConfigInstance(), shardInfos); 21 | } 22 | 23 | public RedisInfo(String host, int port) { 24 | this.host = host; 25 | this.port = port; 26 | initThePool(); 27 | } 28 | 29 | public RedisInfo(String host, int port,String auth) { 30 | this.host = host; 31 | this.port = port; 32 | this.auth = auth; 33 | initThePool(); 34 | } 35 | 36 | public String getHost() { 37 | return host; 38 | } 39 | 40 | public int getPort() { 41 | return port; 42 | } 43 | 44 | public String getAuth() { 45 | return auth; 46 | } 47 | 48 | @Override 49 | public boolean equals(Object obj) { 50 | if (obj instanceof RedisInfo) { 51 | RedisInfo hp = (RedisInfo) obj; 52 | 53 | String thisHost = convertHost(host); 54 | String hpHost = convertHost(hp.host); 55 | return port == hp.port && thisHost.equals(hpHost); 56 | 57 | } 58 | 59 | return false; 60 | } 61 | 62 | public ShardedJedisPool getShardedJedisPool() { 63 | return shardedJedisPool; 64 | } 65 | 66 | @Override 67 | public String toString() { 68 | return host + ":" + port; 69 | } 70 | 71 | private String convertHost(String host) { 72 | if (host.equals("127.0.0.1")) 73 | return LOCALHOST_STR; 74 | else if (host.equals("::1")) 75 | return LOCALHOST_STR; 76 | 77 | return host; 78 | } 79 | } -------------------------------------------------------------------------------- /chapter9/.gitignore: -------------------------------------------------------------------------------- 1 | /bin/ 2 | /build/ 3 | -------------------------------------------------------------------------------- /chapter9/.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | chapter5 4 | 5 | 6 | 7 | 8 | 9 | org.eclipse.jdt.core.javabuilder 10 | 11 | 12 | 13 | 14 | 15 | org.springsource.ide.eclipse.gradle.core.nature 16 | org.eclipse.jdt.core.javanature 17 | 18 | 19 | -------------------------------------------------------------------------------- /chapter9/README.md: -------------------------------------------------------------------------------- 1 | Netty Cookbook - chapter 9 code -------------------------------------------------------------------------------- /chapter9/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'java' 2 | apply plugin: 'eclipse' 3 | 4 | sourceCompatibility = 1.8 5 | 6 | version = '1.0' 7 | 8 | repositories { 9 | mavenCentral() 10 | } 11 | 12 | dependencies { 13 | compile ( 14 | // common 15 | 'io.netty:netty-all:4.0.25.Final' 16 | ,'commons-io:commons-io:2.4' 17 | ,'org.apache.commons:commons-lang3:3.3.2' 18 | ,'log4j:log4j:1.2.17' 19 | ,'org.slf4j:slf4j-log4j12:1.7.7' 20 | ,'org.yaml:snakeyaml:1.14' 21 | 22 | ,'com.google.code.gson:gson:2.3' 23 | ,'com.google.guava:guava:18.0' 24 | ,'org.twitter4j:twitter4j-core:4.0.2' 25 | ,'org.twitter4j:twitter4j-stream:4.0.2' 26 | ,'redis.clients:jedis:2.6.2' 27 | ,'com.github.jknack:handlebars:2.0.0' 28 | 29 | ) 30 | testCompile group: 'junit', name: 'junit', version: '4.11' 31 | } 32 | -------------------------------------------------------------------------------- /chapter9/src/main/java/chapter4/recipe1/WebSocketServer.java: -------------------------------------------------------------------------------- 1 | package chapter4.recipe1; 2 | 3 | 4 | /** 5 | * @author toddf 6 | * @since June 29, 2012 7 | */ 8 | public class WebSocketServer { 9 | 10 | 11 | public static void main(String[] args) { 12 | } 13 | } -------------------------------------------------------------------------------- /chapter9/src/main/java/chapter4/recipe2/RealtimeWebSocketIO.java: -------------------------------------------------------------------------------- 1 | package chapter4.recipe2; 2 | 3 | public class RealtimeWebSocketIO { 4 | 5 | } 6 | -------------------------------------------------------------------------------- /chapter9/src/main/java/chapter4/recipe3/ChatServerWithSTOMP.java: -------------------------------------------------------------------------------- 1 | package chapter4.recipe3; 2 | 3 | public class ChatServerWithSTOMP { 4 | 5 | } 6 | -------------------------------------------------------------------------------- /chapter9/src/main/java/chapter4/recipe4/RealtimeWidgetServer.java: -------------------------------------------------------------------------------- 1 | package chapter4.recipe4; 2 | 3 | public class RealtimeWidgetServer { 4 | 5 | } 6 | -------------------------------------------------------------------------------- /chapter9/src/main/java/log4j.properties: -------------------------------------------------------------------------------- 1 | # Root logger option 2 | log4j.rootLogger=INFO, stdout 3 | 4 | # Redirect log messages to console 5 | log4j.appender.stdout=org.apache.log4j.ConsoleAppender 6 | log4j.appender.stdout.Target=System.out 7 | log4j.appender.stdout.layout=org.apache.log4j.PatternLayout 8 | log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n 9 | 10 | # Redirect log messages to a log file, support file rolling. 11 | log4j.appender.file=org.apache.log4j.RollingFileAppender 12 | log4j.appender.file.File=./log/java-cookbook-demo 13 | log4j.appender.file.MaxFileSize=5MB 14 | log4j.appender.file.MaxBackupIndex=10 15 | log4j.appender.file.layout=org.apache.log4j.PatternLayout 16 | log4j.appender.file.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n -------------------------------------------------------------------------------- /chapter9/src/main/java/netty/cookbook/common/CallbackProcessor.java: -------------------------------------------------------------------------------- 1 | package netty.cookbook.common; 2 | 3 | @FunctionalInterface 4 | public interface CallbackProcessor { 5 | public void process(Object obj); 6 | } -------------------------------------------------------------------------------- /chapter9/src/main/java/netty/cookbook/common/CharPool.java: -------------------------------------------------------------------------------- 1 | package netty.cookbook.common; 2 | 3 | public class CharPool { 4 | 5 | public static final char AMPERSAND = '&'; 6 | 7 | public static final char APOSTROPHE = '\''; 8 | 9 | public static final char AT = '@'; 10 | 11 | public static final char BACK_SLASH = '\\'; 12 | 13 | public static final char CLOSE_BRACKET = ']'; 14 | 15 | public static final char CLOSE_CURLY_BRACE = '}'; 16 | 17 | public static final char CLOSE_PARENTHESIS = ')'; 18 | 19 | public static final char COLON = ':'; 20 | 21 | public static final char COMMA = ','; 22 | 23 | public static final char DASH = '-'; 24 | 25 | public static final char EQUAL = '='; 26 | 27 | public static final char GREATER_THAN = '>'; 28 | 29 | public static final char FORWARD_SLASH = '/'; 30 | 31 | public static final char LESS_THAN = '<'; 32 | 33 | public static final char LOWER_CASE_E = 'e'; 34 | 35 | public static final char MINUS = '-'; 36 | 37 | public static final char NEW_LINE = '\n'; 38 | 39 | public static final char OPEN_BRACKET = '['; 40 | 41 | public static final char OPEN_CURLY_BRACE = '{'; 42 | 43 | public static final char OPEN_PARENTHESIS = '('; 44 | 45 | public static final char PERCENT = '%'; 46 | 47 | public static final char PERIOD = '.'; 48 | 49 | public static final char PIPE = '|'; 50 | 51 | public static final char PLUS = '+'; 52 | 53 | public static final char POUND = '#'; 54 | 55 | public static final char QUESTION = '?'; 56 | 57 | public static final char QUOTE = '\"'; 58 | 59 | public static final char RETURN = '\r'; 60 | 61 | public static final char SEMICOLON = ';'; 62 | 63 | public static final char SLASH = FORWARD_SLASH; 64 | 65 | public static final char SPACE = ' '; 66 | 67 | public static final char STAR = '*'; 68 | 69 | public static final char TILDE = '~'; 70 | 71 | public static final char UNDERLINE = '_'; 72 | 73 | public static final char UPPER_CASE_E = 'E'; 74 | 75 | public static final char TAB = '\t'; 76 | 77 | } 78 | -------------------------------------------------------------------------------- /chapter9/src/main/java/netty/cookbook/common/LogUtil.java: -------------------------------------------------------------------------------- 1 | package netty.cookbook.common; 2 | 3 | public class LogUtil { 4 | 5 | public static void println(Object obj){ 6 | System.out.println(obj); 7 | } 8 | 9 | public static void println(String obj){ 10 | System.out.println(obj); 11 | } 12 | 13 | 14 | } 15 | -------------------------------------------------------------------------------- /chapter9/src/main/java/netty/cookbook/common/TcpChannelHandler.java: -------------------------------------------------------------------------------- 1 | package netty.cookbook.common; 2 | 3 | import io.netty.channel.ChannelHandlerContext; 4 | 5 | @FunctionalInterface 6 | public interface TcpChannelHandler { 7 | public void process(ChannelHandlerContext ctx, Object msg); 8 | } 9 | -------------------------------------------------------------------------------- /chapter9/src/main/java/netty/cookbook/common/UrlUtil.java: -------------------------------------------------------------------------------- 1 | package netty.cookbook.common; 2 | 3 | import java.net.MalformedURLException; 4 | import java.net.URL; 5 | 6 | public class UrlUtil { 7 | public final static String REGEX_FOR_ROOT_DOMAIN = ".*\\.(?=.*\\.)"; 8 | 9 | public static String getRootDomain(String fullUrl) throws MalformedURLException{ 10 | return new URL(fullUrl).getHost().replaceAll(REGEX_FOR_ROOT_DOMAIN, ""); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /chapter9/src/main/java/netty/cookbook/common/http/ContentTypePool.java: -------------------------------------------------------------------------------- 1 | package netty.cookbook.common.http; 2 | 3 | public class ContentTypePool { 4 | public static final String GIF = "image/gif"; 5 | public static final String TRACKING_GIF = GIF; 6 | public static final String JPEG = "image/jpeg"; 7 | 8 | public static final String JAVA_SCRIPT = "application/javascript; charset=utf-8"; 9 | public static final String XML = "application/xml; charset=utf-8"; 10 | public static final String JSON = "application/json; charset=utf-8"; 11 | 12 | public static final String TEXT_UTF8 = "text/plain; charset=UTF-8"; 13 | public static final String HTML_UTF8 = "text/html; charset=UTF-8"; 14 | } 15 | -------------------------------------------------------------------------------- /chapter9/src/main/java/netty/cookbook/common/http/HttpOutputResource.java: -------------------------------------------------------------------------------- 1 | package netty.cookbook.common.http; 2 | 3 | import io.netty.buffer.ByteBuf; 4 | 5 | public class HttpOutputResource { 6 | ByteBuf byteBuf; 7 | long length; 8 | long lastModified; 9 | 10 | 11 | public HttpOutputResource(ByteBuf byteBuf, long lastModified) { 12 | super(); 13 | this.byteBuf = byteBuf; 14 | this.length = byteBuf.readableBytes(); 15 | this.lastModified = lastModified; 16 | } 17 | 18 | public ByteBuf getByteBuf() { 19 | return byteBuf; 20 | } 21 | 22 | public void setByteBuf(ByteBuf byteBuf) { 23 | this.byteBuf = byteBuf; 24 | } 25 | 26 | public long getLength() { 27 | return length; 28 | } 29 | 30 | public void setLength(long length) { 31 | this.length = length; 32 | } 33 | 34 | public long getLastModified() { 35 | return lastModified; 36 | } 37 | 38 | public void setLastModified(long lastModified) { 39 | this.lastModified = lastModified; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /chapter9/src/main/java/netty/cookbook/common/redis/RedisCommand.java: -------------------------------------------------------------------------------- 1 | package netty.cookbook.common.redis; 2 | 3 | import netty.cookbook.common.StringPool; 4 | import redis.clients.jedis.Jedis; 5 | import redis.clients.jedis.ShardedJedis; 6 | import redis.clients.jedis.ShardedJedisPool; 7 | import redis.clients.jedis.exceptions.JedisException; 8 | 9 | public abstract class RedisCommand { 10 | protected ShardedJedisPool jedisPool; 11 | protected ShardedJedis shardedJedis = null; 12 | protected Jedis jedis = null; 13 | 14 | public RedisCommand(ShardedJedisPool jedisPool) { 15 | super(); 16 | if (jedisPool == null) { 17 | throw new IllegalArgumentException("jedisPool is NULL!"); 18 | } 19 | this.jedisPool = jedisPool; 20 | } 21 | 22 | public T execute() { 23 | boolean commited = false; 24 | T rs = null; 25 | try { 26 | shardedJedis = jedisPool.getResource(); 27 | if (shardedJedis != null) { 28 | jedis = shardedJedis.getShard(StringPool.BLANK); 29 | rs = build(); 30 | commited = true; 31 | } 32 | } catch (Exception e) { 33 | e.printStackTrace(); 34 | } finally { 35 | freeRedisResource(jedisPool, shardedJedis, commited); 36 | } 37 | return rs; 38 | } 39 | 40 | public static void freeRedisResource(ShardedJedisPool jedisPool, ShardedJedis shardedJedis, boolean isCommited){ 41 | if (shardedJedis != null && jedisPool != null) { 42 | if (isCommited) { 43 | jedisPool.returnResource(shardedJedis); 44 | } else { 45 | jedisPool.returnBrokenResource(shardedJedis); 46 | } 47 | } 48 | } 49 | 50 | //define the logic at implementer 51 | protected abstract T build() throws JedisException; 52 | } -------------------------------------------------------------------------------- /chapter9/src/main/java/netty/cookbook/common/redis/RedisInfo.java: -------------------------------------------------------------------------------- 1 | package netty.cookbook.common.redis; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | import redis.clients.jedis.JedisShardInfo; 7 | import redis.clients.jedis.ShardedJedisPool; 8 | 9 | public class RedisInfo { 10 | public static final String LOCALHOST_STR = "localhost"; 11 | 12 | private String host; 13 | private int port; 14 | private String auth; 15 | private ShardedJedisPool shardedJedisPool; 16 | 17 | protected void initThePool(){ 18 | List shardInfos = new ArrayList(1); 19 | shardInfos.add(new JedisShardInfo(getHost(), getPort(), 0)); 20 | shardedJedisPool = new ShardedJedisPool(RedisConnectionPoolConfig.getJedisPoolConfigInstance(), shardInfos); 21 | } 22 | 23 | public RedisInfo(String host, int port) { 24 | this.host = host; 25 | this.port = port; 26 | initThePool(); 27 | } 28 | 29 | public RedisInfo(String host, int port,String auth) { 30 | this.host = host; 31 | this.port = port; 32 | this.auth = auth; 33 | initThePool(); 34 | } 35 | 36 | public String getHost() { 37 | return host; 38 | } 39 | 40 | public int getPort() { 41 | return port; 42 | } 43 | 44 | public String getAuth() { 45 | return auth; 46 | } 47 | 48 | @Override 49 | public boolean equals(Object obj) { 50 | if (obj instanceof RedisInfo) { 51 | RedisInfo hp = (RedisInfo) obj; 52 | 53 | String thisHost = convertHost(host); 54 | String hpHost = convertHost(hp.host); 55 | return port == hp.port && thisHost.equals(hpHost); 56 | 57 | } 58 | 59 | return false; 60 | } 61 | 62 | public ShardedJedisPool getShardedJedisPool() { 63 | return shardedJedisPool; 64 | } 65 | 66 | @Override 67 | public String toString() { 68 | return host + ":" + port; 69 | } 70 | 71 | private String convertHost(String host) { 72 | if (host.equals("127.0.0.1")) 73 | return LOCALHOST_STR; 74 | else if (host.equals("::1")) 75 | return LOCALHOST_STR; 76 | 77 | return host; 78 | } 79 | } -------------------------------------------------------------------------------- /netty-cookbook-java-src/.gitignore: -------------------------------------------------------------------------------- 1 | /bin/ 2 | /build/ 3 | -------------------------------------------------------------------------------- /netty-cookbook-java-src/.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | netty-cookbook-java-src 4 | 5 | 6 | 7 | 8 | 9 | org.eclipse.jdt.core.javabuilder 10 | 11 | 12 | 13 | 14 | 15 | org.springsource.ide.eclipse.gradle.core.nature 16 | org.eclipse.jdt.core.javanature 17 | 18 | 19 | -------------------------------------------------------------------------------- /netty-cookbook-java-src/README.txt: -------------------------------------------------------------------------------- 1 | demo asynch programming with traditional blocking IO -------------------------------------------------------------------------------- /netty-cookbook-java-src/configs/redis-connection-pool-configs.json: -------------------------------------------------------------------------------- 1 | { 2 | maxTotal : 3000, 3 | maxIdle : 20, 4 | minIdle : 2, 5 | maxWaitMillis : 5000; 6 | numTestsPerEvictionRun : 10, 7 | testOnBorrow : true, 8 | testOnReturn : true, 9 | testWhileIdle : true, 10 | timeBetweenEvictionRunsMillis : 60000 11 | } -------------------------------------------------------------------------------- /netty-cookbook-java-src/data/text-file.txt: -------------------------------------------------------------------------------- 1 | This is a message in text-file.txt -------------------------------------------------------------------------------- /netty-cookbook-java-src/lib/mongodb-async-driver-2.0.1.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trieu/netty-cookbook/6b72058b2dd085a52c7586ced4899490e8ae52df/netty-cookbook-java-src/lib/mongodb-async-driver-2.0.1.jar -------------------------------------------------------------------------------- /netty-cookbook-java-src/lib/netty-codec-ftp-0.2-SNAPSHOT.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trieu/netty-cookbook/6b72058b2dd085a52c7586ced4899490e8ae52df/netty-cookbook-java-src/lib/netty-codec-ftp-0.2-SNAPSHOT.jar -------------------------------------------------------------------------------- /netty-cookbook-java-src/src/main/avro/mail.avpr: -------------------------------------------------------------------------------- 1 | {"namespace": "avro", 2 | "protocol": "Mail", 3 | 4 | "types": [ 5 | {"name": "Message", "type": "record", 6 | "fields": [ 7 | {"name": "to", "type": "string"}, 8 | {"name": "from", "type": "string"}, 9 | {"name": "body", "type": "string"} 10 | ] 11 | } 12 | ], 13 | 14 | "messages": { 15 | "send": { 16 | "request": [{"name": "message", "type": "Message"}], 17 | "response": "string" 18 | } 19 | } 20 | } -------------------------------------------------------------------------------- /netty-cookbook-java-src/src/main/java/avro/Mail.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Autogenerated by Avro 3 | * 4 | * DO NOT EDIT DIRECTLY 5 | */ 6 | package avro; 7 | 8 | @SuppressWarnings("all") 9 | @org.apache.avro.specific.AvroGenerated 10 | public interface Mail { 11 | public static final org.apache.avro.Protocol PROTOCOL = org.apache.avro.Protocol.parse("{\"protocol\":\"Mail\",\"namespace\":\"avro\",\"types\":[{\"type\":\"record\",\"name\":\"Message\",\"fields\":[{\"name\":\"to\",\"type\":\"string\"},{\"name\":\"from\",\"type\":\"string\"},{\"name\":\"body\",\"type\":\"string\"}]}],\"messages\":{\"send\":{\"request\":[{\"name\":\"message\",\"type\":\"Message\"}],\"response\":\"string\"}}}"); 12 | java.lang.CharSequence send(avro.Message message) throws org.apache.avro.AvroRemoteException; 13 | 14 | @SuppressWarnings("all") 15 | public interface Callback extends Mail { 16 | public static final org.apache.avro.Protocol PROTOCOL = avro.Mail.PROTOCOL; 17 | void send(avro.Message message, org.apache.avro.ipc.Callback callback) throws java.io.IOException; 18 | } 19 | } -------------------------------------------------------------------------------- /netty-cookbook-java-src/src/main/java/log4j.properties: -------------------------------------------------------------------------------- 1 | # Root logger option 2 | log4j.rootLogger=INFO, stdout 3 | 4 | # Redirect log messages to console 5 | log4j.appender.stdout=org.apache.log4j.ConsoleAppender 6 | log4j.appender.stdout.Target=System.out 7 | log4j.appender.stdout.layout=org.apache.log4j.PatternLayout 8 | log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n 9 | 10 | # Redirect log messages to a log file, support file rolling. 11 | log4j.appender.file=org.apache.log4j.RollingFileAppender 12 | log4j.appender.file.File=./log/java-cookbook-demo 13 | log4j.appender.file.MaxFileSize=5MB 14 | log4j.appender.file.MaxBackupIndex=10 15 | log4j.appender.file.layout=org.apache.log4j.PatternLayout 16 | log4j.appender.file.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n -------------------------------------------------------------------------------- /netty-cookbook-java-src/src/main/java/netty/cookbook/chapter1/recipe4/TcpServerInboundHandler.java: -------------------------------------------------------------------------------- 1 | package netty.cookbook.chapter1.recipe4; 2 | 3 | import io.netty.channel.ChannelHandler.Sharable; 4 | import io.netty.channel.ChannelHandlerContext; 5 | import io.netty.channel.ChannelInboundHandlerAdapter; 6 | import io.netty.util.ReferenceCountUtil; 7 | 8 | /** 9 | * Handler implementation for the TCP server. 10 | */ 11 | @Sharable 12 | public class TcpServerInboundHandler extends ChannelInboundHandlerAdapter { 13 | 14 | 15 | @Override 16 | public void channelRead(ChannelHandlerContext ctx, Object msg) { 17 | try { 18 | System.out.println("TcpServerInboundHandler"); 19 | StringBuilder s = new StringBuilder(); 20 | s.append("Ok TCP client, TcpServerInboundHandler got your message \"").append(msg).append("\""); 21 | ctx.write(s); 22 | } finally { 23 | ReferenceCountUtil.release(msg); 24 | } 25 | } 26 | 27 | @Override 28 | public void channelReadComplete(ChannelHandlerContext ctx) { 29 | ctx.flush(); 30 | } 31 | 32 | @Override 33 | public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { 34 | // Close the connection when an exception is raised. 35 | cause.printStackTrace(); 36 | ctx.close(); 37 | } 38 | } -------------------------------------------------------------------------------- /netty-cookbook-java-src/src/main/java/netty/cookbook/chapter1/recipe4/TcpServerOutboundHandler.java: -------------------------------------------------------------------------------- 1 | package netty.cookbook.chapter1.recipe4; 2 | 3 | import io.netty.channel.ChannelHandler.Sharable; 4 | import io.netty.channel.ChannelHandlerContext; 5 | import io.netty.channel.ChannelOutboundHandlerAdapter; 6 | import io.netty.util.concurrent.Future; 7 | import io.netty.util.concurrent.GenericFutureListener; 8 | 9 | /** 10 | * Handler implementation for the TCP server. 11 | */ 12 | @Sharable 13 | public class TcpServerOutboundHandler extends ChannelOutboundHandlerAdapter { 14 | @Override 15 | public void flush(ChannelHandlerContext ctx) throws Exception { 16 | super.flush(ctx); 17 | ctx.close().addListener(new GenericFutureListener>() { 18 | @Override 19 | public void operationComplete(Future future) 20 | throws Exception { 21 | System.out.println("close connection: "+future.isSuccess()); 22 | } 23 | }); 24 | } 25 | 26 | @Override 27 | public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { 28 | // Close the connection when an exception is raised. 29 | cause.printStackTrace(); 30 | ctx.close(); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /netty-cookbook-java-src/src/main/java/netty/cookbook/chapter1/recipe6/DataPipelineProcessingServer.java: -------------------------------------------------------------------------------- 1 | package netty.cookbook.chapter1.recipe6; 2 | 3 | import io.netty.bootstrap.ServerBootstrap; 4 | import io.netty.channel.Channel; 5 | import io.netty.channel.ChannelFuture; 6 | import io.netty.channel.ChannelOption; 7 | import io.netty.channel.EventLoopGroup; 8 | import io.netty.channel.nio.NioEventLoopGroup; 9 | import io.netty.channel.socket.nio.NioServerSocketChannel; 10 | import io.netty.handler.logging.LogLevel; 11 | import io.netty.handler.logging.LoggingHandler; 12 | 13 | public class DataPipelineProcessingServer { 14 | static final int PORT = 8007; 15 | 16 | public static void main(String[] args) throws Exception{ 17 | // Configure the server. 18 | EventLoopGroup bossGroup = new NioEventLoopGroup(1); 19 | EventLoopGroup workerGroup = new NioEventLoopGroup(); 20 | try { 21 | ServerBootstrap b = new ServerBootstrap(); 22 | b.group(bossGroup, workerGroup) 23 | .channel(NioServerSocketChannel.class) 24 | .option(ChannelOption.SO_BACKLOG, 100) 25 | .handler(new LoggingHandler(LogLevel.INFO)) 26 | .childHandler(new DataProcessingPipeline()); 27 | 28 | // Start the server. 29 | ChannelFuture f = b.bind(PORT).sync(); 30 | Channel channel = f.channel(); 31 | 32 | // Wait until the server socket is closed. 33 | channel.closeFuture().sync(); 34 | } finally { 35 | // Shut down all event loops to terminate all threads. 36 | bossGroup.shutdownGracefully(); 37 | workerGroup.shutdownGracefully(); 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /netty-cookbook-java-src/src/main/java/netty/cookbook/chapter2/recipe10/ClientAvroRPC.java: -------------------------------------------------------------------------------- 1 | package netty.cookbook.chapter2.recipe10; 2 | 3 | 4 | import java.io.IOException; 5 | import java.net.InetSocketAddress; 6 | 7 | import netty.cookbook.common.LogUtil; 8 | 9 | import org.apache.avro.ipc.NettyTransceiver; 10 | import org.apache.avro.ipc.specific.SpecificRequestor; 11 | import org.apache.avro.util.Utf8; 12 | 13 | import avro.Mail; 14 | import avro.Message; 15 | 16 | /** 17 | * Start ClientAvroRPC, and send a message. 18 | */ 19 | public class ClientAvroRPC { 20 | public static void main(String[] args) throws IOException { 21 | if(args.length < 3){ 22 | args = new String[] {"someone@example.com","myself@example.com","Hello !"}; 23 | } 24 | NettyTransceiver client = new NettyTransceiver(new InetSocketAddress(10000)); 25 | Mail proxy = (Mail) SpecificRequestor.getClient(Mail.class, client); 26 | LogUtil.println("ClientAvroRPC built OK, got proxy, ready to send data ..."); 27 | Message message = new Message(); 28 | message.setTo(new Utf8(args[0])); 29 | message.setFrom(new Utf8(args[1])); 30 | message.setBody(new Utf8(args[2])); 31 | LogUtil.println("Calling proxy.send with message: " + message.toString()); 32 | LogUtil.println("Result from server: " + proxy.send(message)); 33 | client.close(); 34 | } 35 | } -------------------------------------------------------------------------------- /netty-cookbook-java-src/src/main/java/netty/cookbook/chapter2/recipe10/ProxyServerAvroRPC.java: -------------------------------------------------------------------------------- 1 | package netty.cookbook.chapter2.recipe10; 2 | 3 | import java.io.IOException; 4 | import java.net.InetSocketAddress; 5 | 6 | import netty.cookbook.common.LogUtil; 7 | 8 | import org.apache.avro.ipc.NettyServer; 9 | import org.apache.avro.ipc.Server; 10 | import org.apache.avro.ipc.specific.SpecificResponder; 11 | import org.apache.avro.util.Utf8; 12 | 13 | import avro.Mail; 14 | import avro.Message; 15 | 16 | /** 17 | * @author trieu 18 | * 19 | */ 20 | public class ProxyServerAvroRPC { 21 | public static class MailImpl implements Mail { 22 | public Utf8 send(Message message) { 23 | String s = String.format("message details, to:%s from:%s body:%s", message.getTo(), message.getFrom(), message.getBody()); 24 | LogUtil.println(s); 25 | return new Utf8("Sent OK to "+ message.getTo()); 26 | } 27 | } 28 | private static Server server; 29 | static void startServer() throws IOException { 30 | server = new NettyServer(new SpecificResponder(Mail.class,new MailImpl()), new InetSocketAddress(10000)); 31 | } 32 | public static void main(String[] args) throws Exception { 33 | LogUtil.println("Starting ServerAvroRPC"); 34 | startServer(); 35 | LogUtil.println("ServerAvroRPC started and wait for 15s"); 36 | Thread.sleep(15000); 37 | server.close(); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /netty-cookbook-java-src/src/main/java/netty/cookbook/chapter2/recipe2/Receiver.java: -------------------------------------------------------------------------------- 1 | package netty.cookbook.chapter2.recipe2; 2 | 3 | import io.netty.channel.ChannelHandlerContext; 4 | import io.netty.channel.ChannelInboundHandlerAdapter; 5 | import io.netty.channel.ChannelInitializer; 6 | import io.netty.channel.ChannelPipeline; 7 | import io.netty.channel.socket.SocketChannel; 8 | import io.netty.handler.codec.string.StringDecoder; 9 | import io.netty.handler.codec.string.StringEncoder; 10 | import netty.cookbook.common.BootstrapTemplate; 11 | 12 | public class Receiver { 13 | static final int PORT = 8007; 14 | static final String HOST = "127.0.0.1"; 15 | public static void main(String[] args) throws Exception { 16 | ChannelInitializer initializer = new ChannelInitializer() { 17 | @Override 18 | public void initChannel(SocketChannel ch) throws Exception { 19 | ChannelPipeline p = ch.pipeline(); 20 | p.addLast(new StringEncoder()); 21 | p.addLast(new StringDecoder()); 22 | p.addLast(new ChannelInboundHandlerAdapter() { 23 | @Override 24 | public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { 25 | System.out.println(msg); 26 | ctx.close(); 27 | } 28 | }); 29 | } 30 | }; 31 | BootstrapTemplate.newServerBootstrap(HOST, PORT, initializer); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /netty-cookbook-java-src/src/main/java/netty/cookbook/chapter2/recipe2/Sender.java: -------------------------------------------------------------------------------- 1 | package netty.cookbook.chapter2.recipe2; 2 | 3 | import io.netty.channel.ChannelHandlerContext; 4 | import io.netty.channel.ChannelInboundHandlerAdapter; 5 | import io.netty.channel.ChannelInitializer; 6 | import io.netty.channel.ChannelPipeline; 7 | import io.netty.channel.socket.SocketChannel; 8 | import io.netty.handler.codec.string.StringDecoder; 9 | import io.netty.handler.codec.string.StringEncoder; 10 | import netty.cookbook.common.BootstrapTemplate; 11 | 12 | public class Sender { 13 | static final int PORT = 8007; 14 | static final String HOST = "127.0.0.1"; 15 | 16 | public static void main(String[] args) throws InterruptedException { 17 | final String msg = "This is a long message"; 18 | ChannelInitializer initializer = new ChannelInitializer() { 19 | @Override 20 | public void initChannel(SocketChannel ch) throws Exception { 21 | ChannelPipeline p = ch.pipeline(); 22 | p.addLast(new StringEncoder()); 23 | p.addLast(new StringDecoder()); 24 | p.addLast(new ChannelInboundHandlerAdapter() { 25 | @Override 26 | public void channelActive(ChannelHandlerContext ctx) 27 | throws Exception { 28 | //on ready to send 29 | ctx.writeAndFlush(msg); 30 | } 31 | @Override 32 | public void channelRead(ChannelHandlerContext ctx, 33 | Object data) throws Exception { 34 | //on receive 35 | System.out.println("got " + data); 36 | } 37 | }); 38 | } 39 | }; 40 | BootstrapTemplate.newClientBootstrap(HOST, PORT, initializer ); 41 | Thread.sleep(5000); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /netty-cookbook-java-src/src/main/java/netty/cookbook/chapter2/recipe3/PurchaseClient.java: -------------------------------------------------------------------------------- 1 | package netty.cookbook.chapter2.recipe3; 2 | 3 | import io.netty.channel.ChannelHandler; 4 | import io.netty.channel.ChannelInitializer; 5 | import io.netty.channel.ChannelPipeline; 6 | import io.netty.channel.socket.SocketChannel; 7 | import netty.cookbook.common.BootstrapTemplate; 8 | import netty.cookbook.common.CallbackProcessor; 9 | import netty.cookbook.common.model.PurchaseData; 10 | 11 | public class PurchaseClient { 12 | String host; int port; 13 | public PurchaseClient(String host, int port) { 14 | super(); 15 | this.host = host; 16 | this.port = port; 17 | } 18 | public PurchaseClient send(PurchaseData message, CallbackProcessor asynchCall) throws Exception{ 19 | ChannelHandler clientHandler = new PurchaseClientHandler(message, asynchCall); 20 | ChannelInitializer initializer = new ChannelInitializer() { 21 | @Override 22 | public void initChannel(SocketChannel ch) throws Exception { 23 | ChannelPipeline p = ch.pipeline(); 24 | p.addLast(new PurchaseDataDecoder()); 25 | p.addLast(new PurchaseDataEncoder()); 26 | p.addLast(clientHandler); 27 | } 28 | }; 29 | BootstrapTemplate.newClientBootstrap(host, port, initializer ); 30 | return this; 31 | } 32 | public static void main(String[] args) throws Exception { 33 | int unixTime = (int) (System.currentTimeMillis() / 1000L); 34 | PurchaseData data = new PurchaseData(1001, 499.99f, "Trieu", "Amazon", unixTime, false ); 35 | new PurchaseClient("127.0.0.1",8007).send(data, rs -> { 36 | System.out.println(rs); 37 | }); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /netty-cookbook-java-src/src/main/java/netty/cookbook/chapter2/recipe3/PurchaseDataDecoder.java: -------------------------------------------------------------------------------- 1 | package netty.cookbook.chapter2.recipe3; 2 | 3 | import netty.cookbook.chapter2.recipe6.NettyMonitorIO; 4 | import io.netty.buffer.ByteBuf; 5 | import io.netty.channel.ChannelHandlerContext; 6 | import io.netty.handler.codec.serialization.ClassResolvers; 7 | import io.netty.handler.codec.serialization.ObjectDecoder; 8 | 9 | public class PurchaseDataDecoder extends ObjectDecoder { 10 | public PurchaseDataDecoder() { 11 | super(ClassResolvers.weakCachingConcurrentResolver(null)); 12 | } 13 | @Override 14 | protected Object decode(ChannelHandlerContext ctx, ByteBuf buf) 15 | throws Exception { 16 | Object object = super.decode(ctx, buf); 17 | NettyMonitorIO.updateDataIn(buf); 18 | return object; 19 | } 20 | } -------------------------------------------------------------------------------- /netty-cookbook-java-src/src/main/java/netty/cookbook/chapter2/recipe3/PurchaseDataEncoder.java: -------------------------------------------------------------------------------- 1 | package netty.cookbook.chapter2.recipe3; 2 | 3 | import io.netty.buffer.ByteBuf; 4 | import io.netty.channel.ChannelHandlerContext; 5 | import io.netty.handler.codec.serialization.ObjectEncoder; 6 | 7 | import java.io.Serializable; 8 | 9 | import netty.cookbook.chapter2.recipe6.NettyMonitorIO; 10 | 11 | public class PurchaseDataEncoder extends ObjectEncoder { 12 | @Override 13 | protected void encode(ChannelHandlerContext ctx, Serializable msg, ByteBuf buf) throws Exception { 14 | super.encode(ctx, msg, buf); 15 | NettyMonitorIO.updateDataOut(buf); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /netty-cookbook-java-src/src/main/java/netty/cookbook/chapter2/recipe3/PurchaseServer.java: -------------------------------------------------------------------------------- 1 | package netty.cookbook.chapter2.recipe3; 2 | 3 | import io.netty.channel.ChannelHandlerContext; 4 | import io.netty.channel.ChannelInboundHandlerAdapter; 5 | import io.netty.channel.ChannelInitializer; 6 | import io.netty.channel.ChannelPipeline; 7 | import io.netty.channel.socket.SocketChannel; 8 | import netty.cookbook.common.BootstrapTemplate; 9 | import netty.cookbook.common.model.PurchaseData; 10 | 11 | import org.apache.log4j.Logger; 12 | 13 | public class PurchaseServer { 14 | final static Logger logger = Logger.getLogger(PurchaseServer.class); 15 | 16 | static final int PORT = 8007; 17 | static final String HOST = "127.0.0.1"; 18 | 19 | public static void main(String[] args) throws Exception { 20 | ChannelInitializer initializer = new ChannelInitializer() { 21 | @Override 22 | public void initChannel(SocketChannel ch) throws Exception { 23 | ChannelPipeline p = ch.pipeline(); 24 | p.addLast(new PurchaseDataDecoder()); 25 | p.addLast(new PurchaseDataEncoder()); 26 | p.addLast(new ChannelInboundHandlerAdapter() { 27 | @Override 28 | public void channelRead(ChannelHandlerContext ctx, 29 | Object data) throws Exception { 30 | System.out.println("processed Purchase " + data); 31 | PurchaseData processed = new PurchaseData(data, true); 32 | ctx.writeAndFlush(processed); 33 | } 34 | }); 35 | } 36 | }; 37 | BootstrapTemplate.newServerBootstrap(HOST, PORT, initializer); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /netty-cookbook-java-src/src/main/java/netty/cookbook/chapter2/recipe6/NettyMonitorIO.java: -------------------------------------------------------------------------------- 1 | package netty.cookbook.chapter2.recipe6; 2 | 3 | import io.netty.buffer.ByteBuf; 4 | 5 | import java.text.DateFormat; 6 | import java.text.SimpleDateFormat; 7 | import java.util.Date; 8 | import java.util.Timer; 9 | import java.util.TimerTask; 10 | import java.util.concurrent.ConcurrentHashMap; 11 | import java.util.concurrent.ConcurrentMap; 12 | 13 | /** 14 | * @author trieunt 15 | * 16 | */ 17 | public class NettyMonitorIO { 18 | static final DateFormat DATE_TIME_FORMAT = new SimpleDateFormat("yyyy-MM-dd HH:mm"); 19 | static ConcurrentMap dataOutStats = new ConcurrentHashMap(); 20 | static ConcurrentMap dataInStats = new ConcurrentHashMap(); 21 | public static long updateDataOut(ByteBuf buf) { 22 | String time = DATE_TIME_FORMAT.format(new Date()); 23 | long c = dataOutStats.getOrDefault(time, 0L) + buf.readableBytes(); 24 | dataOutStats.put(time, c); 25 | return c; 26 | } 27 | public static long updateDataIn(ByteBuf buf) { 28 | String time = DATE_TIME_FORMAT.format(new Date()); 29 | long c = dataInStats.getOrDefault(time, 0L) + buf.writableBytes(); 30 | dataInStats.put(time, c); 31 | return c; 32 | } 33 | static { 34 | new Timer(true).schedule(new TimerTask() { 35 | @Override 36 | public void run() { 37 | System.out.println("--------------------------------"); 38 | System.out.println("Data In Stats:"); 39 | dataInStats.forEach((String key, Long val)->{ 40 | System.out.println(key + " : "+val); 41 | }); 42 | System.out.println("Data Out Stats:"); 43 | dataOutStats.forEach((String key, Long val)->{ 44 | System.out.println(key + " : "+val); 45 | }); 46 | } 47 | }, 2000, 2000); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /netty-cookbook-java-src/src/main/java/netty/cookbook/chapter2/recipe7/HeartBeatHandler.java: -------------------------------------------------------------------------------- 1 | package netty.cookbook.chapter2.recipe7; 2 | 3 | import io.netty.buffer.ByteBuf; 4 | import io.netty.buffer.Unpooled; 5 | import io.netty.channel.ChannelHandlerContext; 6 | import io.netty.channel.SimpleChannelInboundHandler; 7 | import io.netty.channel.socket.DatagramPacket; 8 | import io.netty.util.CharsetUtil; 9 | 10 | import java.util.Date; 11 | import java.util.LinkedList; 12 | import java.util.Queue; 13 | import java.util.Timer; 14 | import java.util.TimerTask; 15 | 16 | public class HeartBeatHandler extends 17 | SimpleChannelInboundHandler { 18 | private static final Queue logQueue = new LinkedList(); 19 | static String log(String log) { 20 | return String.valueOf(logQueue.add(log)); 21 | } 22 | static { 23 | new Timer(true).schedule(new TimerTask() { 24 | @Override 25 | public void run() { 26 | while ( ! logQueue.isEmpty() ) { 27 | // log to Kafka or somewhere 28 | String s = logQueue.poll(); 29 | if(s != null){ 30 | System.out.println(s); 31 | } 32 | } 33 | } 34 | }, 1000, 2000); 35 | } 36 | 37 | @Override 38 | public void channelReadComplete(ChannelHandlerContext ctx) { 39 | ctx.flush(); 40 | } 41 | 42 | @Override 43 | public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { 44 | cause.printStackTrace(); 45 | // We don't close the channel because we can keep serving requests. 46 | } 47 | 48 | @Override 49 | protected void channelRead0(ChannelHandlerContext ctx, DatagramPacket packet) throws Exception { 50 | System.err.println(packet); 51 | String s = packet.content().toString(CharsetUtil.UTF_8); 52 | System.out.println(s); 53 | ByteBuf buf = Unpooled.copiedBuffer("I'm alive at "+new Date(), CharsetUtil.UTF_8); 54 | ctx.write(new DatagramPacket(buf, packet.sender())); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /netty-cookbook-java-src/src/main/java/netty/cookbook/chapter2/recipe7/ImportantServer.java: -------------------------------------------------------------------------------- 1 | package netty.cookbook.chapter2.recipe7; 2 | 3 | import io.netty.channel.EventLoopGroup; 4 | import io.netty.channel.nio.NioEventLoopGroup; 5 | import netty.cookbook.common.BootstrapTemplate; 6 | 7 | /** 8 | * @author trieu 9 | * 10 | * demo for HeartBeat monitor 11 | * 12 | */ 13 | public class ImportantServer { 14 | private static final int PORT = 8080; 15 | public static void main(String[] args) throws Exception { 16 | EventLoopGroup loopGroup = new NioEventLoopGroup(); 17 | try { 18 | BootstrapTemplate.newBootstrapUDP(loopGroup, new HeartBeatHandler(), PORT) 19 | .sync().channel().closeFuture().await(); 20 | } finally { 21 | loopGroup.shutdownGracefully(); 22 | } 23 | } 24 | } -------------------------------------------------------------------------------- /netty-cookbook-java-src/src/main/java/netty/cookbook/chapter2/recipe8/SimpleSctpClient.java: -------------------------------------------------------------------------------- 1 | package netty.cookbook.chapter2.recipe8; 2 | 3 | import io.netty.bootstrap.Bootstrap; 4 | import io.netty.channel.ChannelFuture; 5 | import io.netty.channel.ChannelInitializer; 6 | import io.netty.channel.ChannelPipeline; 7 | import io.netty.channel.EventLoopGroup; 8 | import io.netty.channel.nio.NioEventLoopGroup; 9 | import io.netty.channel.sctp.SctpChannel; 10 | import io.netty.channel.sctp.SctpChannelOption; 11 | import io.netty.channel.sctp.nio.NioSctpChannel; 12 | 13 | 14 | public final class SimpleSctpClient { 15 | 16 | static final String HOST = System.getProperty("host", "127.0.0.1"); 17 | static final int PORT = Integer.parseInt(System.getProperty("port", "8007")); 18 | 19 | public static void main(String[] args) throws Exception { 20 | EventLoopGroup loopGroup = new NioEventLoopGroup(); 21 | try { 22 | ChannelFuture f = new Bootstrap().group(loopGroup) 23 | .channel(NioSctpChannel.class) 24 | // set SCTP option 25 | .option(SctpChannelOption.SCTP_NODELAY, true) 26 | .handler(new ChannelInitializer() { 27 | @Override 28 | public void initChannel(SctpChannel ch) throws Exception { 29 | ChannelPipeline p = ch.pipeline(); 30 | p.addLast(new SimpleSctpClientHandler()); 31 | } 32 | }).connect(HOST, PORT).sync(); 33 | f.channel().closeFuture().sync(); 34 | } finally { 35 | loopGroup.shutdownGracefully(); 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /netty-cookbook-java-src/src/main/java/netty/cookbook/chapter2/recipe8/SimpleSctpClientHandler.java: -------------------------------------------------------------------------------- 1 | package netty.cookbook.chapter2.recipe8; 2 | 3 | import io.netty.buffer.ByteBuf; 4 | import io.netty.buffer.Unpooled; 5 | import io.netty.channel.ChannelHandlerContext; 6 | import io.netty.channel.ChannelInboundHandlerAdapter; 7 | import io.netty.channel.sctp.SctpMessage; 8 | import io.netty.util.CharsetUtil; 9 | 10 | 11 | public class SimpleSctpClientHandler extends ChannelInboundHandlerAdapter { 12 | private final ByteBuf firstMessage, secondMessage; 13 | public SimpleSctpClientHandler() { 14 | firstMessage = Unpooled.copiedBuffer("first message",CharsetUtil.UTF_8); 15 | secondMessage = Unpooled.copiedBuffer("second message",CharsetUtil.UTF_8); 16 | } 17 | @Override 18 | public void channelActive(ChannelHandlerContext ctx) { 19 | ctx.write(new SctpMessage(0, 0, firstMessage)); 20 | ctx.write(new SctpMessage(0, 0, secondMessage)); 21 | ctx.flush(); 22 | } 23 | 24 | @Override 25 | public void channelRead(ChannelHandlerContext ctx, Object msg) { 26 | System.out.println(msg); 27 | } 28 | 29 | @Override 30 | public void channelReadComplete(ChannelHandlerContext ctx) { 31 | ctx.flush(); 32 | } 33 | 34 | @Override 35 | public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { 36 | // Close the connection when an exception is raised. 37 | cause.printStackTrace(); 38 | ctx.close(); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /netty-cookbook-java-src/src/main/java/netty/cookbook/chapter2/recipe8/SimpleSctpServer.java: -------------------------------------------------------------------------------- 1 | package netty.cookbook.chapter2.recipe8; 2 | 3 | import io.netty.bootstrap.ServerBootstrap; 4 | import io.netty.channel.ChannelFuture; 5 | import io.netty.channel.ChannelInitializer; 6 | import io.netty.channel.ChannelOption; 7 | import io.netty.channel.ChannelPipeline; 8 | import io.netty.channel.EventLoopGroup; 9 | import io.netty.channel.nio.NioEventLoopGroup; 10 | import io.netty.channel.sctp.SctpChannel; 11 | import io.netty.channel.sctp.nio.NioSctpServerChannel; 12 | import io.netty.handler.logging.LogLevel; 13 | import io.netty.handler.logging.LoggingHandler; 14 | 15 | 16 | public final class SimpleSctpServer { 17 | 18 | static final int PORT = Integer.parseInt(System.getProperty("port", "8007")); 19 | 20 | public static void main(String[] args) throws Exception { 21 | EventLoopGroup mainLoop = new NioEventLoopGroup(1); 22 | EventLoopGroup workerLoop = new NioEventLoopGroup(); 23 | try { 24 | ChannelFuture f = new ServerBootstrap().group(mainLoop, workerLoop) 25 | .channel(NioSctpServerChannel.class) 26 | .option(ChannelOption.SO_BACKLOG, 100) 27 | .handler(new LoggingHandler(LogLevel.INFO)) 28 | .childHandler(new ChannelInitializer() { 29 | @Override 30 | public void initChannel(SctpChannel ch) throws Exception { 31 | ChannelPipeline p = ch.pipeline(); 32 | p.addLast(new SimpleSctpServerHandler()); 33 | } 34 | }).bind(PORT).sync(); 35 | f.channel().closeFuture().sync(); 36 | } finally { 37 | mainLoop.shutdownGracefully(); 38 | workerLoop.shutdownGracefully(); 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /netty-cookbook-java-src/src/main/java/netty/cookbook/chapter2/recipe8/SimpleSctpServerHandler.java: -------------------------------------------------------------------------------- 1 | package netty.cookbook.chapter2.recipe8; 2 | 3 | import io.netty.channel.ChannelHandler.Sharable; 4 | import io.netty.channel.ChannelHandlerContext; 5 | import io.netty.channel.ChannelInboundHandlerAdapter; 6 | import io.netty.channel.sctp.SctpMessage; 7 | import io.netty.util.CharsetUtil; 8 | 9 | /** 10 | * Handler implementation for the SCTP echo server. 11 | */ 12 | @Sharable 13 | public class SimpleSctpServerHandler extends ChannelInboundHandlerAdapter { 14 | @Override 15 | public void channelRead(ChannelHandlerContext ctx, Object msg) { 16 | System.out.println(msg); 17 | if(msg instanceof SctpMessage){ 18 | SctpMessage sctpMsg = (SctpMessage) msg; 19 | System.out.println(sctpMsg.content().toString(CharsetUtil.UTF_8)); 20 | ctx.write(sctpMsg); 21 | } 22 | } 23 | 24 | @Override 25 | public void channelReadComplete(ChannelHandlerContext ctx) { 26 | ctx.flush(); 27 | } 28 | 29 | @Override 30 | public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { 31 | // Close the connection when an exception is raised. 32 | cause.printStackTrace(); 33 | ctx.close(); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /netty-cookbook-java-src/src/main/java/netty/cookbook/chapter2/recipe9/FileReceiver.java: -------------------------------------------------------------------------------- 1 | package netty.cookbook.chapter2.recipe9; 2 | 3 | import java.io.File; 4 | import java.io.IOException; 5 | import java.io.InputStream; 6 | import java.nio.file.Files; 7 | 8 | import com.butor.netty.handler.codec.ftp.DataReceiver; 9 | 10 | class FileReceiver implements DataReceiver { 11 | @Override 12 | public void receive(String name, InputStream data) throws IOException { 13 | System.out.println("got file: [" + name + "]"); 14 | //copy to local folder 15 | Files.copy(data, new File("./data/"+name).toPath()); 16 | } 17 | } -------------------------------------------------------------------------------- /netty-cookbook-java-src/src/main/java/netty/cookbook/chapter2/recipe9/SimpleServerFTP.java: -------------------------------------------------------------------------------- 1 | package netty.cookbook.chapter2.recipe9; 2 | 3 | import io.netty.channel.ChannelInitializer; 4 | import io.netty.channel.ChannelPipeline; 5 | import io.netty.channel.socket.SocketChannel; 6 | import netty.cookbook.common.BootstrapTemplate; 7 | 8 | import com.butor.netty.handler.codec.ftp.CrlfStringDecoder; 9 | import com.butor.netty.handler.codec.ftp.DataReceiver; 10 | import com.butor.netty.handler.codec.ftp.FtpServerHandler; 11 | import com.butor.netty.handler.codec.ftp.cmd.DefaultCommandExecutionTemplate; 12 | 13 | public class SimpleServerFTP { 14 | public static void main(String... args) throws Exception { 15 | DataReceiver dataReceiver = new FileReceiver(); 16 | final DefaultCommandExecutionTemplate tpl = new DefaultCommandExecutionTemplate(dataReceiver); 17 | ChannelInitializer initializer = new ChannelInitializer() { 18 | @Override 19 | protected void initChannel(SocketChannel ch) throws Exception { 20 | ChannelPipeline p = ch.pipeline(); 21 | p.addLast(new CrlfStringDecoder()); 22 | p.addLast(new FtpServerHandler(tpl)); 23 | } 24 | }; 25 | BootstrapTemplate.newServerBootstrap("127.0.0.1", 2121, initializer); 26 | } 27 | } -------------------------------------------------------------------------------- /netty-cookbook-java-src/src/main/java/netty/cookbook/chapter3/recipe1/Echo.java: -------------------------------------------------------------------------------- 1 | package netty.cookbook.chapter3.recipe1; 2 | 3 | import org.jboss.netty.handler.codec.http.HttpMethod; 4 | import org.restexpress.Request; 5 | import org.restexpress.Response; 6 | import org.restexpress.RestExpress; 7 | 8 | /** 9 | * @author toddf 10 | * @since June 29, 2012 11 | */ 12 | public class Echo { 13 | static class RestfulHandler { 14 | public String read(Request req, Response res) { 15 | String value = req.getHeader("echo"); 16 | res.setContentType("text/xml"); 17 | 18 | if (value == null) { 19 | return "no value specified"; 20 | } else { 21 | return String.format( 22 | "%s", value); 23 | } 24 | } 25 | } 26 | 27 | public static void main(String[] args) { 28 | RestExpress server = new RestExpress().setName("Echo"); 29 | 30 | server.uri("/echo", new RestfulHandler()).method(HttpMethod.GET) 31 | .noSerialization(); 32 | 33 | server.bind(8000); 34 | server.awaitShutdown(); 35 | } 36 | } -------------------------------------------------------------------------------- /netty-cookbook-java-src/src/main/java/netty/cookbook/chapter4/recipe5/PubSubDemo.java: -------------------------------------------------------------------------------- 1 | package netty.cookbook.chapter4.recipe5; 2 | 3 | import netty.cookbook.chapter4.recipe5.WebUrl.FacebookStats; 4 | 5 | public class PubSubDemo { 6 | 7 | public static void main(String[] args) { 8 | WebUrl model = new WebUrl("http://vnexpress.net"); 9 | SocialAnalyticUpdater observer = new SocialAnalyticUpdater(model); 10 | 11 | for (FacebookStats stats : model.getFacebookStats()) { 12 | stats.setLikeCount(stats.getLikeCount() + 1); 13 | } 14 | 15 | for (FacebookStats stats : model.getFacebookStats()) { 16 | stats.setShareCount(stats.getShareCount() + 1); 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /netty-cookbook-java-src/src/main/java/netty/cookbook/chapter4/recipe5/SocialAnalyticUpdater.java: -------------------------------------------------------------------------------- 1 | package netty.cookbook.chapter4.recipe5; 2 | 3 | import java.beans.PropertyChangeEvent; 4 | import java.beans.PropertyChangeListener; 5 | 6 | public class SocialAnalyticUpdater implements PropertyChangeListener { 7 | public SocialAnalyticUpdater(WebUrl model) { 8 | model.addChangeListener(this); 9 | } 10 | 11 | @Override 12 | public void propertyChange(PropertyChangeEvent event) { 13 | System.out.println("Changed property: " + event.getPropertyName() + " [old -> " 14 | + event.getOldValue() + "] | [new -> " + event.getNewValue() +"]"); 15 | } 16 | } -------------------------------------------------------------------------------- /netty-cookbook-java-src/src/main/java/netty/cookbook/chapter4/recipe5/WebUrl.java: -------------------------------------------------------------------------------- 1 | package netty.cookbook.chapter4.recipe5; 2 | 3 | import java.beans.PropertyChangeEvent; 4 | import java.beans.PropertyChangeListener; 5 | import java.util.ArrayList; 6 | import java.util.List; 7 | 8 | public class WebUrl { 9 | public static final String LIKE_COUNT = "likeCount"; 10 | public static final String SHARE_COUNT = "shareCount"; 11 | 12 | private List stats = new ArrayList(); 13 | private List listener = new ArrayList(); 14 | private String url; 15 | 16 | public class FacebookStats { 17 | private long likeCount; 18 | private long shareCount; 19 | 20 | public FacebookStats(long like, long share) { 21 | this.likeCount = like; 22 | this.shareCount = share; 23 | } 24 | 25 | public long getLikeCount() { 26 | return likeCount; 27 | } 28 | 29 | public void setLikeCount(long like) { 30 | notifyListeners(this, LIKE_COUNT, this.likeCount, this.likeCount = like); 31 | 32 | } 33 | 34 | public long getShareCount() { 35 | return shareCount; 36 | } 37 | 38 | public void setShareCount(long shareCount) { 39 | notifyListeners(this, SHARE_COUNT, this.shareCount, this.shareCount = shareCount); 40 | } 41 | } 42 | 43 | public List getFacebookStats() { 44 | return stats; 45 | } 46 | 47 | public String getUrl() { 48 | return url; 49 | } 50 | 51 | public WebUrl(String url) { 52 | this.url = url; 53 | stats.add(new FacebookStats(0, 0)); 54 | } 55 | 56 | private void notifyListeners(Object object, String property, 57 | long oldValue, long newValue) { 58 | for (PropertyChangeListener name : listener) { 59 | name.propertyChange(new PropertyChangeEvent(this, property, oldValue, newValue)); 60 | } 61 | } 62 | 63 | public void addChangeListener(PropertyChangeListener newListener) { 64 | listener.add(newListener); 65 | } 66 | 67 | } -------------------------------------------------------------------------------- /netty-cookbook-java-src/src/main/java/netty/cookbook/chapter8/recipe3/HttpServer.java: -------------------------------------------------------------------------------- 1 | package netty.cookbook.chapter8.recipe3; 2 | 3 | 4 | import netty.cookbook.common.BootstrapTemplate; 5 | 6 | 7 | public class HttpServer { 8 | static String host = "localhost:8080"; 9 | 10 | public final static String DEFAULT_CLASSPATH = "rfx"; 11 | public final static String SERVER_INFO_VERSION = "RfxS2Http/0.1"; 12 | 13 | int port; 14 | String ip; 15 | 16 | static boolean debug = false; 17 | 18 | public final static void setDebug(boolean debug) { 19 | HttpServer.debug = debug; 20 | } 21 | 22 | public final static boolean isDebug() { 23 | return debug; 24 | } 25 | 26 | void setHost(String ip, int port) { 27 | this.port = port; 28 | this.ip = ip; 29 | host = this.ip+":"+port; 30 | } 31 | 32 | public HttpServer(String ip, int port) { 33 | setHost(ip, port); 34 | } 35 | 36 | public static String getHost() { 37 | return host; 38 | } 39 | 40 | public void run() throws Exception { 41 | BootstrapTemplate.newHttpServerBootstrap(ip, port, new PublicHttpServerInitializer()); 42 | } 43 | 44 | public static void main(String[] args) throws Exception { 45 | HttpServer httpServer = new HttpServer("*", 3001); 46 | httpServer.run(); 47 | } 48 | } -------------------------------------------------------------------------------- /netty-cookbook-java-src/src/main/java/netty/cookbook/chapter8/recipe3/PublicHttpServerInitializer.java: -------------------------------------------------------------------------------- 1 | package netty.cookbook.chapter8.recipe3; 2 | 3 | 4 | import io.netty.channel.ChannelInitializer; 5 | import io.netty.channel.ChannelPipeline; 6 | import io.netty.channel.socket.SocketChannel; 7 | import io.netty.handler.codec.http.HttpRequestDecoder; 8 | import io.netty.handler.codec.http.HttpResponseEncoder; 9 | 10 | public class PublicHttpServerInitializer extends ChannelInitializer { 11 | 12 | @Override 13 | public void initChannel(SocketChannel ch) throws Exception { 14 | // Create a default pipeline implementation. 15 | ChannelPipeline p = ch.pipeline(); 16 | 17 | // Uncomment the following line if you want HTTPS 18 | //SSLEngine engine = SecureChatSslContextFactory.getServerContext().createSSLEngine(); 19 | //engine.setUseClientMode(false); 20 | //p.addLast("ssl", new SslHandler(engine)); 21 | //TODO support SSL HTTP 22 | 23 | p.addLast("decoder", new HttpRequestDecoder()); 24 | // Uncomment the following line if you don't want to handle HttpChunks. 25 | //p.addLast("aggregator", new HttpObjectAggregator(1048576)); 26 | p.addLast("encoder", new HttpResponseEncoder()); 27 | // Remove the following line if you don't want automatic content compression. 28 | //p.addLast("deflater", new HttpContentCompressor()); 29 | p.addLast("handler", new HttpEventProcessingHandler()); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /netty-cookbook-java-src/src/main/java/netty/cookbook/common/CallbackActor.java: -------------------------------------------------------------------------------- 1 | package netty.cookbook.common; 2 | 3 | import akka.actor.UntypedActor; 4 | 5 | public class CallbackActor extends UntypedActor { 6 | 7 | @Override 8 | public void onReceive(Object arg0) throws Exception { 9 | // TODO Auto-generated method stub 10 | 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /netty-cookbook-java-src/src/main/java/netty/cookbook/common/CallbackProcessor.java: -------------------------------------------------------------------------------- 1 | package netty.cookbook.common; 2 | 3 | @FunctionalInterface 4 | public interface CallbackProcessor { 5 | public void process(Object obj); 6 | } -------------------------------------------------------------------------------- /netty-cookbook-java-src/src/main/java/netty/cookbook/common/LogUtil.java: -------------------------------------------------------------------------------- 1 | package netty.cookbook.common; 2 | 3 | public class LogUtil { 4 | 5 | public static void println(Object obj){ 6 | System.out.println(obj); 7 | } 8 | 9 | public static void println(String obj){ 10 | System.out.println(obj); 11 | } 12 | 13 | 14 | } 15 | -------------------------------------------------------------------------------- /netty-cookbook-java-src/src/main/java/netty/cookbook/common/TcpChannelHandler.java: -------------------------------------------------------------------------------- 1 | package netty.cookbook.common; 2 | 3 | import io.netty.channel.ChannelHandlerContext; 4 | 5 | @FunctionalInterface 6 | public interface TcpChannelHandler { 7 | public void process(ChannelHandlerContext ctx, Object msg); 8 | } 9 | -------------------------------------------------------------------------------- /netty-cookbook-java-src/src/main/java/netty/cookbook/common/UrlUtil.java: -------------------------------------------------------------------------------- 1 | package netty.cookbook.common; 2 | 3 | import java.net.MalformedURLException; 4 | import java.net.URL; 5 | 6 | public class UrlUtil { 7 | public final static String REGEX_FOR_ROOT_DOMAIN = ".*\\.(?=.*\\.)"; 8 | 9 | public static String getRootDomain(String fullUrl) throws MalformedURLException{ 10 | return new URL(fullUrl).getHost().replaceAll(REGEX_FOR_ROOT_DOMAIN, ""); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /netty-cookbook-java-src/src/main/java/netty/cookbook/common/http/ContentTypePool.java: -------------------------------------------------------------------------------- 1 | package netty.cookbook.common.http; 2 | 3 | public class ContentTypePool { 4 | public static final String GIF = "image/gif"; 5 | public static final String TRACKING_GIF = GIF; 6 | public static final String JPEG = "image/jpeg"; 7 | 8 | public static final String JAVA_SCRIPT = "application/javascript; charset=utf-8"; 9 | public static final String XML = "application/xml; charset=utf-8"; 10 | public static final String JSON = "application/json; charset=utf-8"; 11 | 12 | public static final String TEXT_UTF8 = "text/plain; charset=UTF-8"; 13 | public static final String HTML_UTF8 = "text/html; charset=UTF-8"; 14 | } 15 | -------------------------------------------------------------------------------- /netty-cookbook-java-src/src/main/java/netty/cookbook/common/http/HttpOutputResource.java: -------------------------------------------------------------------------------- 1 | package netty.cookbook.common.http; 2 | 3 | import io.netty.buffer.ByteBuf; 4 | 5 | public class HttpOutputResource { 6 | ByteBuf byteBuf; 7 | long length; 8 | long lastModified; 9 | 10 | 11 | public HttpOutputResource(ByteBuf byteBuf, long lastModified) { 12 | super(); 13 | this.byteBuf = byteBuf; 14 | this.length = byteBuf.readableBytes(); 15 | this.lastModified = lastModified; 16 | } 17 | 18 | public ByteBuf getByteBuf() { 19 | return byteBuf; 20 | } 21 | 22 | public void setByteBuf(ByteBuf byteBuf) { 23 | this.byteBuf = byteBuf; 24 | } 25 | 26 | public long getLength() { 27 | return length; 28 | } 29 | 30 | public void setLength(long length) { 31 | this.length = length; 32 | } 33 | 34 | public long getLastModified() { 35 | return lastModified; 36 | } 37 | 38 | public void setLastModified(long lastModified) { 39 | this.lastModified = lastModified; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /netty-cookbook-java-src/src/main/java/netty/cookbook/common/model/PurchaseData.java: -------------------------------------------------------------------------------- 1 | package netty.cookbook.common.model; 2 | 3 | import java.io.Serializable; 4 | 5 | import com.google.gson.Gson; 6 | 7 | public class PurchaseData implements Serializable{ 8 | private static final long serialVersionUID = -5467453661148034694L; 9 | private final int itemId; 10 | private final float price; 11 | private final String buyer; 12 | private final String seller; 13 | private final int unixTime; 14 | private final boolean processed; 15 | public PurchaseData(int itemId, float price, String buyer, String seller, 16 | int unixTime, boolean processed) { 17 | super(); 18 | this.itemId = itemId; 19 | this.price = price; 20 | this.buyer = buyer; 21 | this.seller = seller; 22 | this.unixTime = unixTime; 23 | this.processed = processed; 24 | } 25 | public PurchaseData(Object obj, boolean processed) { 26 | super(); 27 | PurchaseData data = (PurchaseData)obj; 28 | this.itemId = data.itemId; 29 | this.price = data.price; 30 | this.buyer = data.buyer; 31 | this.seller = data.seller; 32 | this.unixTime = data.unixTime; 33 | this.processed = processed; 34 | } 35 | public float getPrice() { 36 | return price; 37 | } 38 | public String getBuyer() { 39 | return buyer; 40 | } 41 | public String getSeller() { 42 | return seller; 43 | } 44 | public int getUnixTime() { 45 | return unixTime; 46 | } 47 | public int getItemId() { 48 | return itemId; 49 | } 50 | public boolean isProcessed() { 51 | return processed; 52 | } 53 | @Override 54 | public String toString() { 55 | return new Gson().toJson(this); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /netty-cookbook-java-src/src/main/java/netty/cookbook/common/redis/RedisCommand.java: -------------------------------------------------------------------------------- 1 | package netty.cookbook.common.redis; 2 | 3 | import netty.cookbook.common.StringPool; 4 | import redis.clients.jedis.Jedis; 5 | import redis.clients.jedis.ShardedJedis; 6 | import redis.clients.jedis.ShardedJedisPool; 7 | import redis.clients.jedis.exceptions.JedisException; 8 | 9 | public abstract class RedisCommand { 10 | protected ShardedJedisPool jedisPool; 11 | protected ShardedJedis shardedJedis = null; 12 | protected Jedis jedis = null; 13 | 14 | public RedisCommand(ShardedJedisPool jedisPool) { 15 | super(); 16 | if (jedisPool == null) { 17 | throw new IllegalArgumentException("jedisPool is NULL!"); 18 | } 19 | this.jedisPool = jedisPool; 20 | } 21 | 22 | public T execute() { 23 | boolean commited = false; 24 | T rs = null; 25 | try { 26 | shardedJedis = jedisPool.getResource(); 27 | if (shardedJedis != null) { 28 | jedis = shardedJedis.getShard(StringPool.BLANK); 29 | rs = build(); 30 | commited = true; 31 | } 32 | } catch (Exception e) { 33 | e.printStackTrace(); 34 | } finally { 35 | freeRedisResource(jedisPool, shardedJedis, commited); 36 | } 37 | return rs; 38 | } 39 | 40 | public static void freeRedisResource(ShardedJedisPool jedisPool, ShardedJedis shardedJedis, boolean isCommited){ 41 | if (shardedJedis != null && jedisPool != null) { 42 | if (isCommited) { 43 | jedisPool.returnResource(shardedJedis); 44 | } else { 45 | jedisPool.returnBrokenResource(shardedJedis); 46 | } 47 | } 48 | } 49 | 50 | //define the logic at implementer 51 | protected abstract T build() throws JedisException; 52 | } -------------------------------------------------------------------------------- /netty-cookbook-java-src/src/main/java/netty/cookbook/common/redis/RedisInfo.java: -------------------------------------------------------------------------------- 1 | package netty.cookbook.common.redis; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | import redis.clients.jedis.JedisShardInfo; 7 | import redis.clients.jedis.ShardedJedisPool; 8 | 9 | public class RedisInfo { 10 | public static final String LOCALHOST_STR = "localhost"; 11 | 12 | private String host; 13 | private int port; 14 | private String auth; 15 | private ShardedJedisPool shardedJedisPool; 16 | 17 | protected void initThePool(){ 18 | List shardInfos = new ArrayList(1); 19 | shardInfos.add(new JedisShardInfo(getHost(), getPort(), 0)); 20 | shardedJedisPool = new ShardedJedisPool(RedisConnectionPoolConfig.getJedisPoolConfigInstance(), shardInfos); 21 | } 22 | 23 | public RedisInfo(String host, int port) { 24 | this.host = host; 25 | this.port = port; 26 | initThePool(); 27 | } 28 | 29 | public RedisInfo(String host, int port,String auth) { 30 | this.host = host; 31 | this.port = port; 32 | this.auth = auth; 33 | initThePool(); 34 | } 35 | 36 | public String getHost() { 37 | return host; 38 | } 39 | 40 | public int getPort() { 41 | return port; 42 | } 43 | 44 | public String getAuth() { 45 | return auth; 46 | } 47 | 48 | @Override 49 | public boolean equals(Object obj) { 50 | if (obj instanceof RedisInfo) { 51 | RedisInfo hp = (RedisInfo) obj; 52 | 53 | String thisHost = convertHost(host); 54 | String hpHost = convertHost(hp.host); 55 | return port == hp.port && thisHost.equals(hpHost); 56 | 57 | } 58 | 59 | return false; 60 | } 61 | 62 | public ShardedJedisPool getShardedJedisPool() { 63 | return shardedJedisPool; 64 | } 65 | 66 | @Override 67 | public String toString() { 68 | return host + ":" + port; 69 | } 70 | 71 | private String convertHost(String host) { 72 | if (host.equals("127.0.0.1")) 73 | return LOCALHOST_STR; 74 | else if (host.equals("::1")) 75 | return LOCALHOST_STR; 76 | 77 | return host; 78 | } 79 | } -------------------------------------------------------------------------------- /netty-cookbook-java-src/src/test/java/classic/tcp/TCPClient.java: -------------------------------------------------------------------------------- 1 | package classic.tcp; 2 | 3 | import java.io.BufferedReader; 4 | import java.io.DataOutputStream; 5 | import java.io.InputStreamReader; 6 | import java.net.Socket; 7 | 8 | class TCPClient { 9 | public static void main(String argv[]) throws Exception { 10 | String sentence = "hello"; 11 | String modifiedSentence; 12 | //BufferedReader inFromUser = new BufferedReader(new InputStreamReader(System.in)); 13 | Socket clientSocket = new Socket("localhost", 6789); 14 | DataOutputStream outToServer = new DataOutputStream( 15 | clientSocket.getOutputStream()); 16 | BufferedReader inFromServer = new BufferedReader(new InputStreamReader( 17 | clientSocket.getInputStream())); 18 | //sentence = inFromUser.readLine(); 19 | outToServer.writeBytes(sentence + '\n'); 20 | modifiedSentence = inFromServer.readLine(); 21 | System.out.println("FROM SERVER: " + modifiedSentence); 22 | clientSocket.close(); 23 | } 24 | } -------------------------------------------------------------------------------- /netty-cookbook-java-src/src/test/java/classic/tcp/TCPServer.java: -------------------------------------------------------------------------------- 1 | package classic.tcp; 2 | 3 | import java.io.BufferedReader; 4 | import java.io.DataOutputStream; 5 | import java.io.InputStreamReader; 6 | import java.net.ServerSocket; 7 | import java.net.Socket; 8 | 9 | public class TCPServer { 10 | public static void main(String argv[]) throws Exception { 11 | String clientSentence; 12 | String capitalizedSentence; 13 | ServerSocket welcomeSocket = new ServerSocket(6789); 14 | while (true) { 15 | Socket connectionSocket = welcomeSocket.accept(); 16 | BufferedReader inFromClient = new BufferedReader( 17 | new InputStreamReader(connectionSocket.getInputStream())); 18 | DataOutputStream outToClient = new DataOutputStream( 19 | connectionSocket.getOutputStream()); 20 | clientSentence = inFromClient.readLine(); 21 | System.out.println("Received: " + clientSentence); 22 | capitalizedSentence = clientSentence.toUpperCase() + '\n'; 23 | outToClient.writeBytes(capitalizedSentence); 24 | } 25 | //welcomeSocket.close(); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /netty-cookbook-java-src/tools/avro-tools-1.7.7.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trieu/netty-cookbook/6b72058b2dd085a52c7586ced4899490e8ae52df/netty-cookbook-java-src/tools/avro-tools-1.7.7.jar --------------------------------------------------------------------------------