From a4f2629563c4170ad6edc1f6de0caed602ba6f44 Mon Sep 17 00:00:00 2001 From: Trustin Lee Date: Sat, 3 Dec 2011 19:54:11 +0900 Subject: [PATCH] Separate the user guide out of the project. --- src/docbook/css/jbossorg.css | 132 --- src/docbook/en-US/custom.dtd | 88 -- src/docbook/en-US/master.xml | 63 -- src/docbook/en-US/module/appendix.xml | 24 - src/docbook/en-US/module/architecture.xml | 346 ------ src/docbook/en-US/module/codec.xml | 24 - src/docbook/en-US/module/preface.xml | 87 -- src/docbook/en-US/module/security.xml | 24 - src/docbook/en-US/module/start.xml | 1163 --------------------- src/docbook/en-US/module/state-mgmt.xml | 24 - src/docbook/en-US/module/template.xml | 24 - src/docbook/en-US/module/threading.xml | 24 - src/docbook/en-US/module/transport.xml | 24 - src/docbook/images/architecture.odg | Bin 17072 -> 0 bytes src/docbook/images/architecture.png | Bin 49776 -> 0 bytes src/docbook/xslt/eclipse.xsl | 25 - src/docbook/xslt/pdf.xsl | 153 --- src/docbook/xslt/xhtml-single.xsl | 25 - src/docbook/xslt/xhtml.xsl | 25 - 19 files changed, 2275 deletions(-) delete mode 100644 src/docbook/css/jbossorg.css delete mode 100644 src/docbook/en-US/custom.dtd delete mode 100644 src/docbook/en-US/master.xml delete mode 100644 src/docbook/en-US/module/appendix.xml delete mode 100644 src/docbook/en-US/module/architecture.xml delete mode 100644 src/docbook/en-US/module/codec.xml delete mode 100644 src/docbook/en-US/module/preface.xml delete mode 100644 src/docbook/en-US/module/security.xml delete mode 100644 src/docbook/en-US/module/start.xml delete mode 100644 src/docbook/en-US/module/state-mgmt.xml delete mode 100644 src/docbook/en-US/module/template.xml delete mode 100644 src/docbook/en-US/module/threading.xml delete mode 100644 src/docbook/en-US/module/transport.xml delete mode 100644 src/docbook/images/architecture.odg delete mode 100644 src/docbook/images/architecture.png delete mode 100644 src/docbook/xslt/eclipse.xsl delete mode 100644 src/docbook/xslt/pdf.xsl delete mode 100644 src/docbook/xslt/xhtml-single.xsl delete mode 100644 src/docbook/xslt/xhtml.xsl 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 f68b75909f0a4fdf4a6f19e87cdff48d59910092..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 17072 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
    ^_-1BVojniV&QL8lMp;Cn80I`$^dK#LWvszxy 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 JN<= - - - - - - - - - 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 -