diff --git a/src/docbook/css/jbossorg.css b/src/docbook/css/jbossorg.css deleted file mode 100644 index c036504b0e..0000000000 --- a/src/docbook/css/jbossorg.css +++ /dev/null @@ -1,132 +0,0 @@ -/* - * Copyright 2009 Red Hat, Inc. - * - * Red Hat licenses this file to you under the Apache License, version 2.0 - * (the "License"); you may not use this file except in compliance with the - * License. You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. - */ - -@import url("documentation.css"); -@import url("docnav.css"); -@import url("reports.css"); -@import url("extensions.css"); -@import url("codehighlight.css"); - -body { - background-image:url(../images/community/bkg_gradient.gif); - background-repeat:repeat-x; - margin:0 auto; - font-family:'Lucida Grande', Geneva, Verdana, Arial, sans-serif; - font-size:12px; - max-width:55em; - padding:0em 2em; - color:#333; - line-height:150%; - text-align:justify; -} - -/* Links */ - -a:link {color:#0066cc;} - -a:visited {color:#6699cc;} - -div.longdesc-link { - float:right; - color:#999; -} - -/* Headings */ - -h1, h2, h3, h4, h5, h6 { - color:#4a5d75; - line-height:130%; - margin-top:0em; - font-family:'Lucida Grande', Geneva, Verdana, Arial, sans-serif; - background-color:transparent; -} - -h1 { - background-image:url(../images/community/title_hdr.png); - background-repeat:no-repeat; - border-top:1px dotted #CCCCCC; - line-height:1.2em; - color:#182737; - font-size:2em; - padding:1.5em; -} - -h2 {font-size:1.6em;} - -h3 { - font-size:1.3em; - padding-top:0em; - padding-bottom:0em; -} - -h4 { - font-size:1.1em; - padding-top:0em; - padding-bottom:0em; -} - -h5.formalpara { - font-size:1em; - margin-top:2em; - margin-bottom:.8em; -} - -/* Element rules */ - -hr { - border-collapse:collapse; - border-style:none; - border-top:1px dotted #ccc; - width:100% !important; -} - -sup {color:#999;} - -/* Custom overrides */ - -tt, tt *, pre, pre *, code, code * { - font-size: 100% !important; - font-family: "Liberation Mono", "DejaVu Sans Mono", Consolas, Monaco, "Vera Sans Mono", "Lucida Console", "Courier New", monospace !important; -} - -pre a:link * {color:#0066cc !important;} - -pre a:visited * {color:#6699cc !important;} - -.programlisting, .programlistingco pre { - line-height: 160%; -} - -.programlisting img { - margin: 0; - padding: 0; - vertical-align: middle; -} - -span.co { - position: relative; - left: 0; - top: 0; - margin: 0 0; - padding: 0 0; - height: 17px; - float: right; -} - -span.co * { - margin: 0 0; - padding: 0 0; -} diff --git a/src/docbook/en-US/custom.dtd b/src/docbook/en-US/custom.dtd deleted file mode 100644 index 202ca02a26..0000000000 --- a/src/docbook/en-US/custom.dtd +++ /dev/null @@ -1,88 +0,0 @@ - - - - - - - - - - - - - -Bootstrap"> -ClientBootstrap"> -ServerBootstrap"> - - - -ChannelBuffer"> -ChannelBuffers"> - - - -Channel"> -ChannelDownstreamHandler"> -ChannelEvent"> -ChannelFactory"> -ChannelFuture"> -ChannelFutureListener"> -ChannelHandler"> -ChannelHandlerContext"> -ChannelPipeline"> -ChannelPipelineCoverage"> -ChannelPipelineFactory"> -Channels"> -ChannelStateEvent"> -ChannelUpstreamHandler"> -ExceptionEvent"> -MessageEvent"> -SimpleChannelHandler"> - - - -ChannelGroup"> -ChannelGroupFuture"> -DefaultChannelGroup"> - - - -ServerSocketChannel"> -SocketChannel"> - - - -NioClientSocketChannelFactory"> -NioServerSocketChannelFactory"> - - - -FrameDecoder"> - - - -ProtobufEncoder"> -ProtobufDecoder"> - - - -ReplayingDecoder"> -VoidEnum"> - - -SslHandler"> diff --git a/src/docbook/en-US/master.xml b/src/docbook/en-US/master.xml deleted file mode 100644 index 3eb0e25f7d..0000000000 --- a/src/docbook/en-US/master.xml +++ /dev/null @@ -1,63 +0,0 @@ - - - -%CustomDTD; -]> - - - The Netty Project 3.2 User Guide - The Proven Approach to Rapid Network Application Development - - - - - - - - - - - - - - - - - diff --git a/src/docbook/en-US/module/appendix.xml b/src/docbook/en-US/module/appendix.xml deleted file mode 100644 index ce1391e086..0000000000 --- a/src/docbook/en-US/module/appendix.xml +++ /dev/null @@ -1,24 +0,0 @@ - - - -%CustomDTD; -]> - - Additional Resources - To be written... - diff --git a/src/docbook/en-US/module/architecture.xml b/src/docbook/en-US/module/architecture.xml deleted file mode 100644 index 5e4f883c91..0000000000 --- a/src/docbook/en-US/module/architecture.xml +++ /dev/null @@ -1,346 +0,0 @@ - - - -%CustomDTD; -]> - - Architectural Overview - - - - - - - The Architecture Diagram of Netty - - - - - In this chapter, we will examine what core functionalities are provided in - Netty and how they constitute a complete network application development - stack on top of the core. Please keep this diagram in mind as you read this - chapter. - - -
- Rich Buffer Data Structure - - Netty uses its own buffer API instead of NIO ByteBuffer - to represent a sequence of bytes. This approach has significant advantages - over using ByteBuffer. Netty's new buffer type, - &ChannelBuffer; has been designed from the ground up to address the problems - of ByteBuffer and to meet the daily needs of - network application developers. To list a few cool features: - - - - You can define your own buffer type if necessary. - - - - - Transparent zero copy is achieved by a built-in composite buffer type. - - - - - A dynamic buffer type is provided out-of-the-box, whose capacity is - expanded on demand, just like StringBuffer. - - - - - There's no need to call flip() anymore. - - - - - It is often faster than ByteBuffer. - - - - - - For more information, please refer to the - org.jboss.netty.buffer package description. - -
- -
- Universal Asynchronous I/O API - - Traditional I/O APIs in Java provide different types and methods for - different transport types. For example, - java.net.Socket and - java.net.DatagramSocket do not have any common - super type and therefore they have very different ways to perform socket - I/O. - - - This mismatch makes porting a network application from one transport to - another tedious and difficult. The lack of portability between - transports becomes a problem when you need to support additional - transports, as this often entails rewriting the network layer of the - application. Logically, many protocols can run on more than one - transport such as TCP/IP, UDP/IP, SCTP, and serial port communication. - - - To make matters worse, Java's New I/O (NIO) API introduced - incompatibilities with the old blocking I/O (OIO) API and will continue - to do so in the next release, NIO.2 (AIO). Because all these APIs are - different from each other in design and performance characteristics, you - are often forced to determine which API your application will depend on - before you even begin the implementation phase. - - - For instance, you might want to start with OIO because the number of - clients you are going to serve will be very small and writing a socket - server using OIO is much easier than using NIO. However, you are going - to be in trouble when your business grows exponentially and your server - needs to serve tens of thousands of clients simultaneously. You could - start with NIO, but doing so may hinder rapid development by greatly - increasing development time due to the complexity of the NIO Selector - API. - - - Netty has a universal asynchronous I/O interface called a &Channel;, which - abstracts away all operations required for point-to-point communication. - That is, once you wrote your application on one Netty transport, your - application can run on other Netty transports. Netty provides a number - of essential transports via one universal API: - - - - NIO-based TCP/IP transport - (See org.jboss.netty.channel.socket.nio), - - - - - OIO-based TCP/IP transport - (See org.jboss.netty.channel.socket.oio), - - - - OIO-based UDP/IP transport, and - - - - Local transport (See org.jboss.netty.channel.local). - - - - Switching from one transport to another usually takes just a couple - lines of changes such as choosing a different &ChannelFactory; - implementation. - - - Also, you are even able to take advantage of new transports which aren't - yet written (such as serial port communication transport), again - by replacing just a couple lines of constructor calls. Moreover, you can - write your own transport by extending the core API. - -
- -
- Event Model based on the Interceptor Chain Pattern - - A well-defined and extensible event model is a must for an event-driven - application. Netty has a well-defined event model focused on I/O. It - also allows you to implement your own event type without breaking the - existing code because each event type is distinguished from another by - a strict type hierarchy. This is another differentiator against other - frameworks. Many NIO frameworks have no or a very limited notion of an - event model. If they offer extension at all, they often break the - existing code when you try to add custom event types - - - A &ChannelEvent; is handled by a list of &ChannelHandler;s in a - &ChannelPipeline;. The pipeline implements an advanced form of the - Intercepting Filter - pattern to give a user full control over how an event is handled and how - the handlers in the pipeline interact with each other. For example, - you can define what to do when data is read from a socket: - - public class MyReadHandler implements &SimpleChannelHandler; { - public void messageReceived(&ChannelHandlerContext; ctx, &MessageEvent; evt) { - Object message = evt.getMessage(); - // Do something with the received message. - ... - - // And forward the event to the next handler. - ctx.sendUpstream(evt); - } -} - - You can also define what to do when a handler receives a write request: - - public class MyWriteHandler implements &SimpleChannelHandler; { - public void writeRequested(&ChannelHandlerContext; ctx, &MessageEvent; evt) { - Object message = evt.getMessage(); - // Do something with the message to be written. - ... - - // And forward the event to the next handler. - ctx.sendDownstream(evt); - } -} - - For more information on the event model, please refer to the - API documentation of &ChannelEvent; and &ChannelPipeline;. - -
- -
- Advanced Components for More Rapid Development - - On top of the core components mentioned above, that already enable the - implementation of all types of network applications, Netty provides a set - of advanced features to accelerate the page of development even more. - - -
- Codec framework - - As demonstrated in , it is always a good - idea to separate a protocol codec from business logic. However, there - are some complications when implementing this idea from scratch. You - have to deal with the fragmentation of messages. Some protocols are - multi-layered (i.e. built on top of other lower level protocols). Some - are too complicated to be implemented in a single state machine. - - - Consequently, a good network application framework should provide an - extensible, reusable, unit-testable, and multi-layered codec framework - that generates maintainable user codecs. - - - Netty provides a number of basic and advanced codecs to address most - issues you will encounter when you write a protocol codec regardless - if it is simple or not, binary or text - simply whatever. - -
- -
- SSL / TLS Support - - Unlike old blocking I/O, it is a non-trivial task to support SSL in NIO. - You can't simply wrap a stream to encrypt or decrypt data but you have - to use javax.net.ssl.SSLEngine. - SSLEngine is a state machine which is as complex - as SSL itself. You have to manage all possible states such as cipher - suite and encryption key negotiation (or re-negotiation), certificate - exchange, and validation. Moreover, SSLEngine is - not even completely thread-safe, as one would expect. - - - In Netty, &SslHandler; takes care of all the gory details and pitfalls - of SSLEngine. All you need to do is to configure - the &SslHandler; and insert it into your &ChannelPipeline;. It also - allows you to implement advanced features like - StartTLS - very easily. - -
- -
- HTTP Implementation - - HTTP is definitely the most popular protocol in the Internet. There are - already a number of HTTP implementations such as a Servlet container. - Then why does Netty have HTTP on top of its core? - - - Netty's HTTP support is very different from the existing HTTP libraries. - It gives you complete control over how HTTP messages are exchanged at a - low level. Because it is basically the combination of an HTTP codec and - HTTP message classes, there is no restriction such as an enforced thread - model. That is, you can write your own HTTP client or server that works - exactly the way you want. You have full control over everything that's - in the HTTP specification, including the thread model, connection life - cycle, and chunked encoding. - - - Thanks to its highly customizable nature, you can write a very efficient - HTTP server such as: - - - - Chat server that requires persistent connections and server push - technology (e.g. Comet - and WebSockets) - - - - - Media streaming server that needs to keep the connection open - until the whole media is streamed (e.g. 2 hours of video) - - - - - File server that allows the uploading of large files without - memory pressure (e.g. uploading 1GB per request) - - - - - Scalable mash-up client that connects to tens of thousands of 3rd - party web services asynchronously - - - - -
- -
- Google Protocol Buffer Integration - - Google Protocol Buffers - are an ideal solution for the rapid implementation of a highly efficient - binary protocols that evolve over time. With &ProtobufEncoder; and - &ProtobufDecoder;, you can turn the message classes generated by the - Google Protocol Buffers Compiler (protoc) into Netty codec. Please take - a look into the - 'LocalTime' example - that shows how easily you can create a high-performing binary protocol - client and server from the - sample protocol definition. - -
-
- -
- Summary - - In this chapter, we reviewed the overall architecture of Netty from the - feature standpoint. Netty has a simple, yet powerful architecture. - It is composed of three components - buffer, channel, and event model - - and all advanced features are built on top of the three core components. - Once you understood how these three work together, it should not be - difficult to understand the more advanced features which were covered - briefly in this chapter. - - - You might still have unanswered questions about what the overall - architecture looks like exactly and how each of the features work - together. If so, it is a good idea to - talk to us to improve this guide. - -
-
diff --git a/src/docbook/en-US/module/codec.xml b/src/docbook/en-US/module/codec.xml deleted file mode 100644 index 1016148500..0000000000 --- a/src/docbook/en-US/module/codec.xml +++ /dev/null @@ -1,24 +0,0 @@ - - - -%CustomDTD; -]> - - Encoders and Decoders - To be written... - diff --git a/src/docbook/en-US/module/preface.xml b/src/docbook/en-US/module/preface.xml deleted file mode 100644 index 989fc63828..0000000000 --- a/src/docbook/en-US/module/preface.xml +++ /dev/null @@ -1,87 +0,0 @@ - - - -%CustomDTD; -]> - - Preface - -
- The Problem - - Nowadays we use general purpose applications or libraries to communicate - with each other. For example, we often use an HTTP client library to - retrieve information from a web server and to invoke a remote procedure - call via web services. - - - However, a general purpose protocol or its implementation sometimes - does not scale very well. It is like we don't use a general purpose - HTTP server to exchange huge files, e-mail messages, and near-realtime - messages such as financial information and multiplayer game data. - What's required is a highly optimized protocol implementation which is - dedicated to a special purpose. For example, you might want to - implement an HTTP server which is optimized for AJAX-based chat - application, media streaming, or large file transfer. You could even - want to design and implement a whole new protocol which is precisely - tailored to your need. - - - Another inevitable case is when you have to deal with a legacy - proprietary protocol to ensure the interoperability with an old system. - What matters in this case is how quickly we can implement that protocol - while not sacrificing the stability and performance of the resulting - application. - -
- -
- The Solution - - The Netty project is - an effort to provide an asynchronous event-driven network application - framework and tooling for the rapid development of maintainable - high-performance · high-scalability protocol servers and clients. - - - In other words, Netty is a NIO client server framework which enables - quick and easy development of network applications such as protocol - servers and clients. It greatly simplifies and streamlines network - programming such as TCP and UDP socket server development. - - - 'Quick and easy' does not mean that a resulting application will suffer - from a maintainability or a performance issue. Netty has been designed - carefully with the experiences earned from the implementation of a lot - of protocols such as FTP, SMTP, HTTP, and various binary and text-based - legacy protocols. As a result, Netty has succeeded to find a way to - achieve ease of development, performance, stability, and flexibility - without a compromise. - - - Some users might already have found other network application - framework that claims to have the same advantage, and you might want - to ask what makes Netty so different from them. The answer is the - philosophy where it is built on. Netty is designed to give you the most - comfortable experience both in terms of the API and the implementation - from the day one. It is not something tangible but you will realize that - this philosophy will make your life much easier as you read this guide - and play with Netty. - -
-
diff --git a/src/docbook/en-US/module/security.xml b/src/docbook/en-US/module/security.xml deleted file mode 100644 index 039aaf6e94..0000000000 --- a/src/docbook/en-US/module/security.xml +++ /dev/null @@ -1,24 +0,0 @@ - - - -%CustomDTD; -]> - - Securing the Wire - To be written... - diff --git a/src/docbook/en-US/module/start.xml b/src/docbook/en-US/module/start.xml deleted file mode 100644 index 73a86f4aa7..0000000000 --- a/src/docbook/en-US/module/start.xml +++ /dev/null @@ -1,1163 +0,0 @@ - - - -%CustomDTD; -]> - - Getting Started - - This chapter tours around the core constructs of Netty with simple - examples to let you get started quickly. You will be able to write a - client and a server on top of Netty right away when you are at the - end of this chapter. - - - - If you prefer top-down approach in learning something, you might want to - start from and get back here. - - -
- Before Getting Started - - The minimum requirements to run the examples which are introduced in - this chapter are only two; the latest version of Netty and JDK 1.5 or - above. The latest version of Netty is available in - the project download page. To download - the right version of JDK, please refer to your preferred JDK vendor's web - site. - - - As you read, you might have more questions about the classes introduced - in this chapter. Please refer to the API reference whenever you want to - know more about them. All class names in this document are linked to the - online API reference for your convenience. Also, please don't hesitate to - contact the Netty project community and - let us know if there's any incorrect information, errors in grammar and - typo, and if you have a good idea to improve the documentation. - -
- -
- Writing a Discard Server - - The most simplistic protocol in the world is not 'Hello, World!' but - DISCARD. It's - a protocol which discards any received data without any response. - - - To implement the DISCARD protocol, the only thing you need to do is - to ignore all received data. Let us start straight from the handler - implementation, which handles I/O events generated by Netty. - - package org.jboss.netty.example.discard; - -public class DiscardServerHandler extends &SimpleChannelHandler; { - - @Override - public void messageReceived(&ChannelHandlerContext; ctx, &MessageEvent; e) { - } - - @Override - public void exceptionCaught(&ChannelHandlerContext; ctx, &ExceptionEvent; e) { - e.getCause().printStackTrace(); - - &Channel; ch = e.getChannel(); - ch.close(); - } -} - - - - DiscardServerHandler extends - &SimpleChannelHandler;, which is an implementation of - &ChannelHandler;. &SimpleChannelHandler; provides various event - handler methods that you can override. For now, it is just enough - to extend &SimpleChannelHandler; rather than to implement - the handler interfaces by yourself. - - - - - We override the messageReceived event - handler method here. This method is called with a &MessageEvent;, - which contains the received data, whenever new data is received - from a client. In this example, we ignore the received data by doing - nothing to implement the DISCARD protocol. - - - - - exceptionCaught event handler method is - called with an &ExceptionEvent; when an exception was raised by - Netty due to I/O error or by a handler implementation due to the - exception thrown while processing events. In most cases, the - caught exception should be logged and its associated channel - should be closed here, although the implementation of this method - can be different depending on what you want to do to deal with an - exceptional situation. For example, you might want to send a - response message with an error code before closing the connection. - - - - - So far so good. We have implemented the first half of the DISCARD server. - What's left now is to write the main method - which starts the server with the DiscardServerHandler. - - package org.jboss.netty.example.discard; - -import java.net.InetSocketAddress; -import java.util.concurrent.Executors; - -public class DiscardServer { - - public static void main(String[] args) throws Exception { - &ChannelFactory; factory = - new &NioServerSocketChannelFactory;( - Executors.newCachedThreadPool(), - Executors.newCachedThreadPool()); - - &ServerBootstrap; bootstrap = new &ServerBootstrap;(factory); - - bootstrap.setPipelineFactory(new &ChannelPipelineFactory;() { - public &ChannelPipeline; getPipeline() { - return &Channels;.pipeline(new DiscardServerHandler()); - } - }); - - bootstrap.setOption("child.tcpNoDelay", true); - bootstrap.setOption("child.keepAlive", true); - - bootstrap.bind(new InetSocketAddress(8080)); - } -} - - - - &ChannelFactory; is a factory which creates and manages &Channel;s - and its related resources. It processes all I/O requests and - performs I/O to generate &ChannelEvent;s. Netty provides various - &ChannelFactory; implementations. We are implementing a server-side - application in this example, and therefore - &NioServerSocketChannelFactory; was used. Another thing to note is - that it does not create I/O threads by itself. It is supposed to - acquire threads from the thread pool you specified in the - constructor, and it gives you more control over how threads should - be managed in the environment where your application runs, such as - an application server with a security manager. - - - - - &ServerBootstrap; is a helper class that sets up a server. You can - set up the server using a &Channel; directly. However, please note - that this is a tedious process and you do not need to do that in most - cases. - - - - - Here, we configure the &ChannelPipelineFactory;. Whenever a new - connection is accepted by the server, a new &ChannelPipeline; will be - created by the specified &ChannelPipelineFactory;. The new pipeline - contains the DiscardServerHandler. As the - application gets complicated, it is likely that you will add more - handlers to the pipeline and extract this anonymous class into a top - level class eventually. - - - - - You can also set the parameters which are specific to the &Channel; - implementation. We are writing a TCP/IP server, so we are allowed - to set the socket options such as tcpNoDelay and - keepAlive. Please note that the - "child." prefix was added to all options. It - means the options will be applied to the accepted &Channel;s instead - of the options of the &ServerSocketChannel;. You could do the - following to set the options of the &ServerSocketChannel;: - bootstrap.setOption("reuseAddress", true); - - - - - We are ready to go now. What's left is to bind to the port and to - start the server. Here, we bind to the port 8080 - of all NICs (network interface cards) in the machine. You can now - call the bind method as many times as - you want (with different bind addresses.) - - - - - Congratulations! You've just finished your first server on top of Netty. - -
- -
- Looking into the Received Data - - Now that we have written our first server, we need to test if it really - works. The easiest way to test it is to use the telnet - command. For example, you could enter "telnet localhost - 8080" in the command line and type something. - - - However, can we say that the server is working fine? We cannot really - know that because it is a discard server. You will not get any response - at all. To prove it is really working, let us modify the server to print - what it has received. - - - We already know that &MessageEvent; is generated whenever data is - received and the messageReceived handler method - will be invoked. Let us put some code into the - messageReceived method of the - DiscardServerHandler: - - @Override -public void messageReceived(&ChannelHandlerContext; ctx, &MessageEvent; e) { - &ChannelBuffer; buf = (ChannelBuffer) e.getMessage(); - while(buf.readable()) { - System.out.println((char) buf.readByte()); - System.out.flush(); - } -} - - - - It is safe to assume the message type in socket transports is always - &ChannelBuffer;. &ChannelBuffer; is a fundamental data structure - which stores a sequence of bytes in Netty. It's similar to NIO - ByteBuffer, but it is easier to use and more - flexible. For example, Netty allows you to create a composite - &ChannelBuffer; which combines multiple &ChannelBuffer;s reducing - the number of unnecessary memory copy. - - - Although it resembles to NIO ByteBuffer a lot, - it is highly recommended to refer to the API reference. Learning how - to use &ChannelBuffer; correctly is a critical step in using Netty - without difficulty. - - - - - If you run the telnet command again, you will see the - server prints what has received. - - - The full source code of the discard server is located in the - org.jboss.netty.example.discard package of the - distribution. - -
-
- Writing an Echo Server - - So far, we have been consuming data without responding at all. A server, - however, is usually supposed to respond to a request. Let us learn how to - write a response message to a client by implementing the - ECHO protocol, - where any received data is sent back. - - - The only difference from the discard server we have implemented in the - previous sections is that it sends the received data back instead of - printing the received data out to the console. Therefore, it is enough - again to modify the messageReceived method: - - @Override -public void messageReceived(&ChannelHandlerContext; ctx, &MessageEvent; e) { - &Channel; ch = e.getChannel(); - ch.write(e.getMessage()); -} - - - - A &ChannelEvent; object has a reference to its associated &Channel;. - Here, the returned &Channel; represents the connection which received - the &MessageEvent;. We can get the &Channel; and call the - write method to write something back to - the remote peer. - - - - - If you run the telnet command again, you will see the - server sends back whatever you have sent to it. - - - The full source code of the echo server is located in the - org.jboss.netty.example.echo package of the - distribution. - -
- -
- Writing a Time Server - - The protocol to implement in this section is the - TIME protocol. - It is different from the previous examples in that it sends a message, - which contains a 32-bit integer, without receiving any requests and - loses the connection once the message is sent. In this example, you - will learn how to construct and send a message, and to close the - connection on completion. - - - Because we are going to ignore any received data but to send a message - as soon as a connection is established, we cannot use the - messageReceived method this time. Instead, - we should override the channelConnected method. - The following is the implementation: - - package org.jboss.netty.example.time; - -public class TimeServerHandler extends &SimpleChannelHandler; { - - @Override - public void channelConnected(&ChannelHandlerContext; ctx, &ChannelStateEvent; e) { - &Channel; ch = e.getChannel(); - - &ChannelBuffer; time = &ChannelBuffers;.buffer(4); - time.writeInt((int) (System.currentTimeMillis() / 1000)); - - &ChannelFuture; f = ch.write(time); - - f.addListener(new &ChannelFutureListener;() { - public void operationComplete(&ChannelFuture; future) { - &Channel; ch = future.getChannel(); - ch.close(); - } - }); - } - - @Override - public void exceptionCaught(&ChannelHandlerContext; ctx, &ExceptionEvent; e) { - e.getCause().printStackTrace(); - e.getChannel().close(); - } -} - - - - As explained, channelConnected method will - be invoked when a connection is established. Let us write the 32-bit - integer that represents the current time in seconds here. - - - - - To send a new message, we need to allocate a new buffer which will - contain the message. We are going to write a 32-bit integer, and - therefore we need a &ChannelBuffer; whose capacity is - 4 bytes. The &ChannelBuffers; helper class is - used to allocate a new buffer. Besides the - buffer method, &ChannelBuffers; provides a - lot of useful methods related to the &ChannelBuffer;. For more - information, please refer to the API reference. - - - On the other hand, it is a good idea to use static imports for - &ChannelBuffers;: - import static org.jboss.netty.buffer.&ChannelBuffers;.*; -... -&ChannelBuffer; dynamicBuf = dynamicBuffer(256); -&ChannelBuffer; ordinaryBuf = buffer(1024); - - - - - As usual, we write the constructed message. - - - But wait, where's the flip? Didn't we used - to call ByteBuffer.flip() before sending a - message in NIO? &ChannelBuffer; does not have such a method because - it has two pointers; one for read operations and the other for write - operations. The writer index increases when you write something to - a &ChannelBuffer; while the reader index does not change. The reader - index and the writer index represents where the message starts and - ends respectively. - - - In contrast, NIO buffer does not provide a clean way to figure out - where the message content starts and ends without calling the - flip method. You will be in trouble when - you forget to flip the buffer because nothing or incorrect data will - be sent. Such an error does not happen in Netty because we have - different pointer for different operation types. You will find it - makes your life much easier as you get used to it -- a life without - flipping out! - - - Another point to note is that the write - method returns a &ChannelFuture;. A &ChannelFuture; represents an - I/O operation which has not yet occurred. It means, any requested - operation might not have been performed yet because all operations - are asynchronous in Netty. For example, the following code might - close the connection even before a message is sent: - - &Channel; ch = ...; -ch.write(message); -ch.close(); - - Therefore, you need to call the close - method after the &ChannelFuture;, which was returned by the - write method, notifies you when the write - operation has been done. Please note that, close - also might not close the connection immediately, and it returns a - &ChannelFuture;. - - - - - How do we get notified when the write request is finished then? - This is as simple as adding a &ChannelFutureListener; to the returned - &ChannelFuture;. Here, we created a new anonymous &ChannelFutureListener; - which closes the &Channel; when the operation is done. - - - Alternatively, you could simplify the code using a pre-defined - listener: - f.addListener(&ChannelFutureListener;.CLOSE); - - - -
- -
- Writing a Time Client - - Unlike DISCARD and ECHO servers, we need a client for the TIME protocol - because a human cannot translate a 32-bit binary data into a date on a - calendar. In this section, we discuss how to make sure the server works - correctly and learn how to write a client with Netty. - - - The biggest and only difference between a server and a client in Netty - is that different &Bootstrap; and &ChannelFactory; are required. Please - take a look at the following code: - - package org.jboss.netty.example.time; - -import java.net.InetSocketAddress; -import java.util.concurrent.Executors; - -public class TimeClient { - - public static void main(String[] args) throws Exception { - String host = args[0]; - int port = Integer.parseInt(args[1]); - - &ChannelFactory; factory = - new &NioClientSocketChannelFactory;( - Executors.newCachedThreadPool(), - Executors.newCachedThreadPool()); - - &ClientBootstrap; bootstrap = new &ClientBootstrap;(factory); - - bootstrap.setPipelineFactory(new &ChannelPipelineFactory;() { - public &ChannelPipeline; getPipeline() { - return &Channels;.pipeline(new TimeClientHandler()); - } - }); - - bootstrap.setOption("tcpNoDelay", true); - bootstrap.setOption("keepAlive", true); - - bootstrap.connect(new InetSocketAddress(host, port)); - } -} - - - - &NioClientSocketChannelFactory;, instead of &NioServerSocketChannelFactory; - was used to create a client-side &Channel;. - - - - - &ClientBootstrap; is a client-side counterpart of &ServerBootstrap;. - - - - - Please note that there's no "child." prefix. - A client-side &SocketChannel; does not have a parent. - - - - - We should call the connect method instead of - the bind method. - - - - - As you can see, it is not really different from the server side startup. - What about the &ChannelHandler; implementation? It should receive a - 32-bit integer from the server, translate it into a human readable format, - print the translated time, and close the connection: - - package org.jboss.netty.example.time; - -import java.util.Date; - -public class TimeClientHandler extends &SimpleChannelHandler; { - - @Override - public void messageReceived(&ChannelHandlerContext; ctx, &MessageEvent; e) { - &ChannelBuffer; buf = (&ChannelBuffer;) e.getMessage(); - long currentTimeMillis = buf.readInt() * 1000L; - System.out.println(new Date(currentTimeMillis)); - e.getChannel().close(); - } - - @Override - public void exceptionCaught(&ChannelHandlerContext; ctx, &ExceptionEvent; e) { - e.getCause().printStackTrace(); - e.getChannel().close(); - } -} - - It looks very simple and does not look any different from the server side - example. However, this handler sometimes will refuse to work raising an - IndexOutOfBoundsException. We discuss why - this happens in the next section. - -
- -
- - Dealing with a Stream-based Transport - -
- - One Small Caveat of Socket Buffer - - - In a stream-based transport such as TCP/IP, received data is stored - into a socket receive buffer. Unfortunately, the buffer of a - stream-based transport is not a queue of packets but a queue of bytes. - It means, even if you sent two messages as two independent packets, an - operating system will not treat them as two messages but as just a - bunch of bytes. Therefore, there is no guarantee that what you read - is exactly what your remote peer wrote. For example, let us assume - that the TCP/IP stack of an operating system has received three packets: - - +-----+-----+-----+ -| ABC | DEF | GHI | -+-----+-----+-----+ - - Because of this general property of a stream-based protocol, there's - high chance of reading them in the following fragmented form in your - application: - - +----+-------+---+---+ -| AB | CDEFG | H | I | -+----+-------+---+---+ - - Therefore, a receiving part, regardless it is server-side or - client-side, should defrag the received data into one or more meaningful - frames that could be easily understood by the - application logic. In case of the example above, the received data - should be framed like the following: - - +-----+-----+-----+ -| ABC | DEF | GHI | -+-----+-----+-----+ -
-
- - The First Solution - - - Now let us get back to the TIME client example. We have the same - problem here. A 32-bit integer is a very small amount of data, and it - is not likely to be fragmented often. However, the problem is that it - can be fragmented, and the possibility of - fragmentation will increase as the traffic increases. - - - The simplistic solution is to create an internal cumulative buffer and - wait until all 4 bytes are received into the internal buffer. The - following is the modified TimeClientHandler - implementation that fixes the problem: - - package org.jboss.netty.example.time; - -import static org.jboss.netty.buffer.&ChannelBuffers;.*; - -import java.util.Date; - -public class TimeClientHandler extends &SimpleChannelHandler; { - - private final &ChannelBuffer; buf = dynamicBuffer(); - - @Override - public void messageReceived(&ChannelHandlerContext; ctx, &MessageEvent; e) { - &ChannelBuffer; m = (&ChannelBuffer;) e.getMessage(); - buf.writeBytes(m); - - if (buf.readableBytes() >= 4) { - long currentTimeMillis = buf.readInt() * 1000L; - System.out.println(new Date(currentTimeMillis)); - e.getChannel().close(); - } - } - - @Override - public void exceptionCaught(&ChannelHandlerContext; ctx, &ExceptionEvent; e) { - e.getCause().printStackTrace(); - e.getChannel().close(); - } -} - - - - A dynamic buffer is a &ChannelBuffer; which - increases its capacity on demand. It's very useful when you don't - know the length of the message. - - - - - First, all received data should be cumulated into - buf. - - - - - And then, the handler must check if buf has enough - data, 4 bytes in this example, and proceed to the actual business - logic. Otherwise, Netty will call the - messageReceived method again when more - data arrives, and eventually all 4 bytes will be cumulated. - - - -
-
- - The Second Solution - - - Although the first solution has resolved the problem with the TIME - client, the modified handler does not look that clean. Imagine a more - complicated protocol which is composed of multiple fields such as a - variable length field. Your &ChannelHandler; implementation will - become unmaintainable very quickly. - - - As you may have noticed, you can add more than one &ChannelHandler; to - a &ChannelPipeline;, and therefore, you can split one monolithic - &ChannelHandler; into multiple modular ones to reduce the complexity of - your application. For example, you could split - TimeClientHandler into two handlers: - - - - TimeDecoder which deals with the - fragmentation issue, and - - - - - the initial simple version of TimeClientHandler. - - - - - - Fortunately, Netty provides an extensible class which helps you write - the first one out of the box: - - package org.jboss.netty.example.time; - -public class TimeDecoder extends &FrameDecoder; { - - @Override - protected Object decode( - &ChannelHandlerContext; ctx, &Channel; channel, &ChannelBuffer; buffer) { - - if (buffer.readableBytes() < 4) { - return null; - } - - return buffer.readBytes(4); - } -} - - - - &FrameDecoder; is an implementation of &ChannelHandler; which - makes it easy to which deals with the fragmentation issue. - - - - - &FrameDecoder; calls decode method with - an internally maintained cumulative buffer whenever new data is - received. - - - - - If null is returned, it means there's not - enough data yet. &FrameDecoder; will call again when there is a - sufficient amount of data. - - - - - If non-null is returned, it means the - decode method has decoded a message - successfully. &FrameDecoder; will discard the read part of its - internal cumulative buffer. Please remember that you don't need - to decode multiple messages. &FrameDecoder; will keep calling - the decoder method until it returns - null. - - - - - Now that we have another handler to insert into the &ChannelPipeline;, - we should modify the &ChannelPipelineFactory; implementation in the - TimeClient: - - bootstrap.setPipelineFactory(new &ChannelPipelineFactory;() { - public &ChannelPipeline; getPipeline() { - return &Channels;.pipeline( - new TimeDecoder(), - new TimeClientHandler()); - } - }); - - If you are an adventurous person, you might want to try the - &ReplayingDecoder; which simplifies the decoder even more. You will - need to consult the API reference for more information though. - - package org.jboss.netty.example.time; - -public class TimeDecoder extends &ReplayingDecoder;<&VoidEnum;> { - - @Override - protected Object decode( - &ChannelHandlerContext; ctx, &Channel; channel, - &ChannelBuffer; buffer, &VoidEnum; state) { - - return buffer.readBytes(4); - } -} - - Additionally, Netty provides out-of-the-box decoders which enables - you to implement most protocols very easily and helps you avoid from - ending up with a monolithic unmaintainable handler implementation. - Please refer to the following packages for more detailed examples: - - - - org.jboss.netty.example.factorial for - a binary protocol, and - - - - - org.jboss.netty.example.telnet for - a text line-based protocol. - - - - -
-
- -
- - Speaking in POJO instead of ChannelBuffer - - - All the examples we have reviewed so far used a &ChannelBuffer; as a - primary data structure of a protocol message. In this section, we will - improve the TIME protocol client and server example to use a - POJO instead of a - &ChannelBuffer;. - - - The advantage of using a POJO in your &ChannelHandler; is obvious; - your handler becomes more maintainable and reusable by separating the - code which extracts information from &ChannelBuffer; out from the - handler. In the TIME client and server examples, we read only one - 32-bit integer and it is not a major issue to use &ChannelBuffer; directly. - However, you will find it is necessary to make the separation as you - implement a real world protocol. - - - First, let us define a new type called UnixTime. - - package org.jboss.netty.example.time; - -import java.util.Date; - -public class UnixTime { - private final int value; - - public UnixTime(int value) { - this.value = value; - } - - public int getValue() { - return value; - } - - @Override - public String toString() { - return new Date(value * 1000L).toString(); - } -} - - We can now revise the TimeDecoder to return - a UnixTime instead of a &ChannelBuffer;. - - @Override -protected Object decode( - &ChannelHandlerContext; ctx, &Channel; channel, &ChannelBuffer; buffer) { - if (buffer.readableBytes() < 4) { - return null; - } - - return new UnixTime(buffer.readInt()); -} - - - - &FrameDecoder; and &ReplayingDecoder; allow you to return an object - of any type. If they were restricted to return only a - &ChannelBuffer;, we would have to insert another &ChannelHandler; - which transforms a &ChannelBuffer; into a - UnixTime. - - - - - With the updated decoder, the TimeClientHandler - does not use &ChannelBuffer; anymore: - - @Override -public void messageReceived(&ChannelHandlerContext; ctx, &MessageEvent; e) { - UnixTime m = (UnixTime) e.getMessage(); - System.out.println(m); - e.getChannel().close(); -} - - Much simpler and elegant, right? The same technique can be applied on - the server side. Let us update the - TimeServerHandler first this time: - - @Override -public void channelConnected(&ChannelHandlerContext; ctx, &ChannelStateEvent; e) { - UnixTime time = new UnixTime(System.currentTimeMillis() / 1000); - &ChannelFuture; f = e.getChannel().write(time); - f.addListener(&ChannelFutureListener;.CLOSE); -} - - Now, the only missing piece is an encoder, which is an implementation of - &ChannelHandler; that translates a UnixTime back - into a &ChannelBuffer;. It's much simpler than writing a decoder because - there's no need to deal with packet fragmentation and assembly when - encoding a message. - - package org.jboss.netty.example.time; - -import static org.jboss.netty.buffer.&ChannelBuffers;.*; - -public class TimeEncoder extends &SimpleChannelHandler; { - - public void writeRequested(&ChannelHandlerContext; ctx, &MessageEvent; e) { - UnixTime time = (UnixTime) e.getMessage(); - - &ChannelBuffer; buf = buffer(4); - buf.writeInt(time.getValue()); - - &Channels;.write(ctx, e.getFuture(), buf); - } -} - - - - An encoder overrides the writeRequested - method to intercept a write request. Please note that the - &MessageEvent; parameter here is the same type which was specified - in messageReceived but they are interpreted - differently. A &ChannelEvent; can be either an - upstream or downstream - event depending on the direction where the event flows. - For instance, a &MessageEvent; can be an upstream event when called - for messageReceived or a downstream event - when called for writeRequested. - Please refer to the API reference to learn more about the difference - between a upstream event and a downstream event. - - - - - Once done with transforming a POJO into a &ChannelBuffer;, you should - forward the new buffer to the previous &ChannelDownstreamHandler; in - the &ChannelPipeline;. &Channels; provides various helper methods - which generates and sends a &ChannelEvent;. In this example, - &Channels;.write(...) method creates a new - &MessageEvent; and sends it to the previous &ChannelDownstreamHandler; - in the &ChannelPipeline;. - - - On the other hand, it is a good idea to use static imports for - &Channels;: - import static org.jboss.netty.channel.&Channels;.*; -... -&ChannelPipeline; pipeline = pipeline(); -write(ctx, e.getFuture(), buf); -fireChannelDisconnected(ctx); - - - - - The last task left is to insert a TimeEncoder - into the &ChannelPipeline; on the server side, and it is left as a - trivial exercise. - -
- -
- - Shutting Down Your Application - - - If you ran the TimeClient, you must have noticed - that the application doesn't exit but just keep running doing nothing. - Looking from the full stack trace, you will also find a couple I/O threads - are running. To shut down the I/O threads and let the application exit - gracefully, you need to release the resources allocated by &ChannelFactory;. - - - The shutdown process of a typical network application is composed of the - following three steps: - - - - Close all server sockets if there are any, - - - - - Close all non-server sockets (i.e. client sockets and accepted - sockets) if there are any, and - - - - - Release all resources used by &ChannelFactory;. - - - - - - To apply the three steps above to the TimeClient, - TimeClient.main() could shut itself down - gracefully by closing the only one client connection and releasing all - resources used by &ChannelFactory;: - - package org.jboss.netty.example.time; - -public class TimeClient { - public static void main(String[] args) throws Exception { - ... - &ChannelFactory; factory = ...; - &ClientBootstrap; bootstrap = ...; - ... - &ChannelFuture; future = bootstrap.connect(...); - future.awaitUninterruptibly(); - if (!future.isSuccess()) { - future.getCause().printStackTrace(); - } - future.getChannel().getCloseFuture().awaitUninterruptibly(); - factory.releaseExternalResources(); - } -} - - - - The connect method of &ClientBootstrap; - returns a &ChannelFuture; which notifies when a connection attempt - succeeds or fails. It also has a reference to the &Channel; which - is associated with the connection attempt. - - - - - Wait for the returned &ChannelFuture; to determine if the connection - attempt was successful or not. - - - - - If failed, we print the cause of the failure to know why it failed. - the getCause() method of &ChannelFuture; will - return the cause of the failure if the connection attempt was neither - successful nor cancelled. - - - - - Now that the connection attempt is over, we need to wait until the - connection is closed by waiting for the closeFuture - of the &Channel;. Every &Channel; has its own closeFuture - so that you are notified and can perform a certain action on closure. - - - Even if the connection attempt has failed the closeFuture - will be notified because the &Channel; will be closed automatically - when the connection attempt fails. - - - - - All connections have been closed at this point. The only task left - is to release the resources being used by &ChannelFactory;. It is as - simple as calling its releaseExternalResources() - method. All resources including the NIO Selectors - and thread pools will be shut down and terminated automatically. - - - - - Shutting down a client was pretty easy, but how about shutting down a - server? You need to unbind from the port and close all open accepted - connections. To do this, you need a data structure that keeps track of - the list of active connections, and it's not a trivial task. Fortunately, - there is a solution, &ChannelGroup;. - - - &ChannelGroup; is a special extension of Java collections API which - represents a set of open &Channel;s. If a &Channel; is added to a - &ChannelGroup; and the added &Channel; is closed, the closed &Channel; - is removed from its &ChannelGroup; automatically. You can also perform - an operation on all &Channel;s in the same group. For instance, you can - close all &Channel;s in a &ChannelGroup; when you shut down your server. - - - To keep track of open sockets, you need to modify the - TimeServerHandler to add a new open &Channel; to - the global &ChannelGroup;, TimeServer.allChannels: - - @Override -public void channelOpen(&ChannelHandlerContext; ctx, &ChannelStateEvent; e) { - TimeServer.allChannels.add(e.getChannel()); -} - - - - Yes, &ChannelGroup; is thread-safe. - - - - - Now that the list of all active &Channel;s are maintained automatically, - shutting down a server is as easy as shutting down a client: - - package org.jboss.netty.example.time; - -public class TimeServer { - - static final &ChannelGroup; allChannels = new &DefaultChannelGroup;("time-server"); - - public static void main(String[] args) throws Exception { - ... - &ChannelFactory; factory = ...; - &ServerBootstrap; bootstrap = ...; - ... - &Channel; channel = bootstrap.bind(...); - allChannels.add(channel); - waitForShutdownCommand(); - &ChannelGroupFuture; future = allChannels.close(); - future.awaitUninterruptibly(); - factory.releaseExternalResources(); - } -} - - - - &DefaultChannelGroup; requires the name of the group as a constructor - parameter. The group name is solely used to distinguish one group - from others. - - - - - The bind method of &ServerBootstrap; - returns a server side &Channel; which is bound to the specified - local address. Calling the close() method - of the returned &Channel; will make the &Channel; unbind from the - bound local address. - - - - - Any type of &Channel;s can be added to a &ChannelGroup; regardless if - it is either server side, client-side, or accepted. Therefore, - you can close the bound &Channel; along with the accepted &Channel;s - in one shot when the server shuts down. - - - - - waitForShutdownCommand() is an imaginary - method that waits for the shutdown signal. You could wait for a - message from a privileged client or the JVM shutdown hook. - - - - - You can perform the same operation on all channels in the same - &ChannelGroup;. In this case, we close all channels, which means - the bound server-side &Channel; will be unbound and all accepted - connections will be closed asynchronously. To notify when all - connections were closed successfully, it returns a &ChannelGroupFuture; - which has a similar role with &ChannelFuture;. - - - -
- -
- - Summary - - - In this chapter, we had a quick tour of Netty with a demonstration on how - to write a fully working network application on top of Netty. More - questions you may have will be covered in the upcoming chapters and the - revised version of this chapter. Please also note that the - community is always waiting for your - questions and ideas to help you and keep improving Netty based on your - feed back. - -
-
diff --git a/src/docbook/en-US/module/state-mgmt.xml b/src/docbook/en-US/module/state-mgmt.xml deleted file mode 100644 index 81625dfee1..0000000000 --- a/src/docbook/en-US/module/state-mgmt.xml +++ /dev/null @@ -1,24 +0,0 @@ - - - -%CustomDTD; -]> - - State Management - To be written... - diff --git a/src/docbook/en-US/module/template.xml b/src/docbook/en-US/module/template.xml deleted file mode 100644 index a0da7b554e..0000000000 --- a/src/docbook/en-US/module/template.xml +++ /dev/null @@ -1,24 +0,0 @@ - - - -%CustomDTD; -]> - - Chapter title - To be written... - diff --git a/src/docbook/en-US/module/threading.xml b/src/docbook/en-US/module/threading.xml deleted file mode 100644 index 94a2111c0a..0000000000 --- a/src/docbook/en-US/module/threading.xml +++ /dev/null @@ -1,24 +0,0 @@ - - - -%CustomDTD; -]> - - Thread Management - To be written... - diff --git a/src/docbook/en-US/module/transport.xml b/src/docbook/en-US/module/transport.xml deleted file mode 100644 index 7bda3673e8..0000000000 --- a/src/docbook/en-US/module/transport.xml +++ /dev/null @@ -1,24 +0,0 @@ - - - -%CustomDTD; -]> - - Transports - To be written... - diff --git a/src/docbook/images/architecture.odg b/src/docbook/images/architecture.odg deleted file mode 100644 index f68b75909f..0000000000 Binary files a/src/docbook/images/architecture.odg and /dev/null differ diff --git a/src/docbook/images/architecture.png b/src/docbook/images/architecture.png deleted file mode 100644 index d8b2c22e7e..0000000000 Binary files a/src/docbook/images/architecture.png and /dev/null differ diff --git a/src/docbook/xslt/eclipse.xsl b/src/docbook/xslt/eclipse.xsl deleted file mode 100644 index 482f138e00..0000000000 --- a/src/docbook/xslt/eclipse.xsl +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - - - - - 1 - diff --git a/src/docbook/xslt/pdf.xsl b/src/docbook/xslt/pdf.xsl deleted file mode 100644 index f3a0b1c67e..0000000000 --- a/src/docbook/xslt/pdf.xsl +++ /dev/null @@ -1,153 +0,0 @@ - - - - - - - - - - - - - - Liberation Serif,serif - - - - - - - Setting 'title.font.family' param= - - - - - - - - - Setting 'body.font.family' param= - - - - - - - - - Setting 'monospace.font.family' param= - - - - - - - - - Setting 'sans.font.family' param= - - - - - - - - - Setting 'programlisting.font' param= - - - - - - - - - - - - - - - - - - normal - - - - - 1em - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - url( - - ) - - - - - - - - - diff --git a/src/docbook/xslt/xhtml-single.xsl b/src/docbook/xslt/xhtml-single.xsl deleted file mode 100644 index a158fab37b..0000000000 --- a/src/docbook/xslt/xhtml-single.xsl +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - - - - - 1 - diff --git a/src/docbook/xslt/xhtml.xsl b/src/docbook/xslt/xhtml.xsl deleted file mode 100644 index 2b261a5b4e..0000000000 --- a/src/docbook/xslt/xhtml.xsl +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - - - - - 1 -