source: nutchez-0.1/tomcat/webapps/docs/printer/aio.html @ 180

Last change on this file since 180 was 66, checked in by waue, 16 years ago

NutchEz - an easy way to nutch

File size: 19.8 KB
Line 
1<html><head><META http-equiv="Content-Type" content="text/html; charset=iso-8859-1"><title>Apache Tomcat 6.0 - Advanced IO and Tomcat</title><meta value="Remy Maucherat" name="author"><meta value="" name="email"></head><body vlink="#525D76" alink="#525D76" link="#525D76" text="#000000" bgcolor="#ffffff"><table cellspacing="0" width="100%" border="0"><!--PAGE HEADER--><tr><td><!--PROJECT LOGO--><a href="http://tomcat.apache.org/"><img border="0" alt="
2      The Apache Tomcat Servlet/JSP Container
3    " align="right" src="./../images/tomcat.gif"></a></td><td><font face="arial,helvetica,sanserif"><h1>Apache Tomcat 6.0</h1></font></td><td><!--APACHE LOGO--><a href="http://www.apache.org/"><img border="0" alt="Apache Logo" align="right" src="./../images/asf-logo.gif"></a></td></tr></table><table cellspacing="4" width="100%" border="0"><!--HEADER SEPARATOR--><tr><td colspan="2"><hr size="1" noshade></td></tr><tr><!--RIGHT SIDE MAIN BODY--><td align="left" valign="top" width="80%"><table cellspacing="4" width="100%" border="0"><tr><td valign="top" align="left"><h1>Apache Tomcat 6.0</h1><h2>Advanced IO and Tomcat</h2></td><td nowrap="true" valign="top" align="right"><img border="0" hspace="0" vspace="0" height="1" width="1" src="./../images/void.gif"></td></tr></table><table cellpadding="2" cellspacing="0" border="0"><tr><td bgcolor="#525D76"><font face="arial,helvetica.sanserif" color="#ffffff"><a name="Introduction"><strong>Introduction</strong></a></font></td></tr><tr><td><blockquote>
4
5  <p>
6    With usage of APR or NIO APIs as the basis of its connectors, Tomcat is
7    able to provide a number of extensions over the regular blocking IO
8    as provided with support for the Servlet API.
9  </p>
10
11  <p>
12    <b>IMPORTANT NOTE: Usage of these features requires using the APR or NIO
13    HTTP connectors. The classic java.io HTTP connector and the AJP connectors
14    do not support them.</b>
15  </p>
16
17  </blockquote></td></tr></table><table cellpadding="2" cellspacing="0" border="0"><tr><td bgcolor="#525D76"><font face="arial,helvetica.sanserif" color="#ffffff"><a name="Comet support"><strong>Comet support</strong></a></font></td></tr><tr><td><blockquote>
18
19  <p>
20    Comet support allows a servlet to process IO aynchronously, recieving
21    events when data is available for reading on the connection (rather than
22    always using a blocking read), and writing data back on connections
23    asychnonously (most likely responding to some event raised from some
24    other source).
25  </p>
26
27  <table cellpadding="2" cellspacing="0" border="0"><tr><td bgcolor="#828DA6"><font face="arial,helvetica.sanserif" color="#ffffff"><a name="CometEvent"><strong>CometEvent</strong></a></font></td></tr><tr><td><blockquote>
28 
29  <p>
30    Servlets which implement the <code>org.apache.catalina.CometProcessor</code>
31    interface will have their event method invoked rather than the usual service
32    method, according to the event which occurred. The event object gives
33    access to the usual request and response objects, which may be used in the
34    usual way. The main difference is that those objects remain valid and fully
35    functional at any time between processing of the BEGIN event until processing
36    an END or ERROR event.
37    The following event types exist:
38  </p>
39 
40  <ul>
41  <li>EventType.BEGIN: will be called at the beginning
42     of the processing of the connection. It can be used to initialize any relevant
43     fields using the request and response objects. Between the end of the processing
44     of this event, and the beginning of the processing of the end or error events,
45     it is possible to use the response object to write data on the open connection.
46     Note that the response object and depedent OutputStream and Writer are still
47     not synchronized, so when they are accessed by multiple threads,
48     synchronization is mandatory. After processing the initial event, the request
49     is considered to be committed.</li>
50  <li>EventType.READ: This indicates that input data is available, and that one read can be made
51       without blocking. The available and ready methods of the InputStream or
52       Reader may be used to determine if there is a risk of blocking: the servlet
53       should read while data is reported available, and can make one additional read
54       should read while data is reported available. When encountering a read error,
55       the servlet should report it by propagating the exception properly. Throwing
56       an exception will cause the error event to be invoked, and the connection
57       will be closed.
58       Alternately, it is also possible to catch any exception, perform clean up
59       on any data structure the servlet may be using, and using the close method
60       of the event. It is not allowed to attempt reading data from the request
61       object outside of the execution of this method.<br>
62       On some platforms, like Windows, a client disconnect is indicated by a READ event.
63       Reading from the stream may result in -1, an IOException or an EOFException.
64       Make sure you properly handle all these three cases.
65       If you don't catch the IOException, Tomcat will instantly invoke your event chain with an ERROR as
66       it catches the error for you, and you will be notified of the error at that time.
67  </li>
68  <li>EventType.END: End may be called to end the processing of the request. Fields that have
69     been initialized in the begin method should be reset. After this event has
70     been processed, the request and response objects, as well as all their dependent
71     objects will be recycled and used to process other requests. End will also be
72     called when data is available and the end of file is reached on the request input
73     (this usually indicates the client has pipelined a request).</li>
74  <li>EventType.ERROR: Error will be called by the container in the case where an IO exception
75     or a similar unrecoverable error occurs on the connection. Fields that have
76     been initialized in the begin method should be reset. After this event has
77     been processed, the request and response objects, as well as all their dependent
78     objects will be recycled and used to process other requests.</li>
79  </ul>
80
81  <p>
82    There are some event subtypes which allow finer processing of events (note: some of these
83    events require usage of the org.apache.catalina.valves.CometConnectionManagerValve valve):
84  </p>
85
86  <ul>
87  <li>EventSubType.TIMEOUT: The connection timed out (sub type of ERROR); note that this ERROR
88    type is not fatal, and the connection will not be closed unless the servlet uses the close
89    method of the event.
90  </li>
91  <li>EventSubType.CLIENT_DISCONNECT: The client connection was closed (sub type of ERROR).
92    method of the event.
93  </li>
94  <li>EventSubType.IOEXCEPTION: An IO exception occurred, such as invalid content, for example,
95    an invalid chunk block (sub type of ERROR).
96  </li>
97  <li>EventSubType.WEBAPP_RELOAD: The web application is being reloaded (sub type of END).
98  </li>
99  <li>EventSubType.SESSION_END: The servlet ended the session (sub type of END).
100  </li>
101  </ul>
102
103  <p>
104    As described above, the typical lifecycle of a Comet request will consist in a series of
105    events such as: BEGIN -&gt; READ -&gt; READ -&gt; READ -&gt; ERROR/TIMEOUT. At any time, the servlet
106    may end processing of the request by using the close method of the event object.
107  </p>
108 
109  </blockquote></td></tr></table>
110
111  <table cellpadding="2" cellspacing="0" border="0"><tr><td bgcolor="#828DA6"><font face="arial,helvetica.sanserif" color="#ffffff"><a name="CometFilter"><strong>CometFilter</strong></a></font></td></tr><tr><td><blockquote>
112 
113  <p>
114    Similar to regular filters, a filter chain is invoked when comet events are processed.
115    These filters should implement the CometFilter interface (which works in the same way as
116    the regular Filter interface), and should be declared and mapped in the deployment
117    descriptor in the same way as a regular filter. The filter chain when processing an event
118    will only include filters which match all the usual mapping rules, and also implement
119    the CometFiler interface.
120  </p>
121 
122  </blockquote></td></tr></table>
123
124  <table cellpadding="2" cellspacing="0" border="0"><tr><td bgcolor="#828DA6"><font face="arial,helvetica.sanserif" color="#ffffff"><a name="Example code"><strong>Example code</strong></a></font></td></tr><tr><td><blockquote>
125 
126  <p>
127    The following pseudo code servlet implments asynchronous chat functionality using the API
128    described above:
129  </p>
130 
131  <div align="left"><table border="0" cellpadding="0" cellspacing="4"><tr><td height="1" width="1" bgcolor="#023264"><img border="0" hspace="0" vspace="0" height="1" width="1" src="./../images/void.gif"></td><td height="1" bgcolor="#023264"><img border="0" hspace="0" vspace="0" height="1" width="1" src="./../images/void.gif"></td><td height="1" width="1" bgcolor="#023264"><img border="0" hspace="0" vspace="0" height="1" width="1" src="./../images/void.gif"></td></tr><tr><td width="1" bgcolor="#023264"><img border="0" hspace="0" vspace="0" height="1" width="1" src="./../images/void.gif"></td><td height="1" bgcolor="#ffffff"><pre>
132public class ChatServlet
133    extends HttpServlet implements CometProcessor {
134
135    protected ArrayList&lt;HttpServletResponse&gt; connections =
136        new ArrayList&lt;HttpServletResponse&gt;();
137    protected MessageSender messageSender = null;
138   
139    public void init() throws ServletException {
140        messageSender = new MessageSender();
141        Thread messageSenderThread =
142            new Thread(messageSender, "MessageSender[" + getServletContext().getContextPath() + "]");
143        messageSenderThread.setDaemon(true);
144        messageSenderThread.start();
145    }
146
147    public void destroy() {
148        connections.clear();
149        messageSender.stop();
150        messageSender = null;
151    }
152
153    /**
154     * Process the given Comet event.
155     *
156     * @param event The Comet event that will be processed
157     * @throws IOException
158     * @throws ServletException
159     */
160    public void event(CometEvent event)
161        throws IOException, ServletException {
162        HttpServletRequest request = event.getHttpServletRequest();
163        HttpServletResponse response = event.getHttpServletResponse();
164        if (event.getEventType() == CometEvent.EventType.BEGIN) {
165            log("Begin for session: " + request.getSession(true).getId());
166            PrintWriter writer = response.getWriter();
167            writer.println("&lt;!doctype html public \"-//w3c//dtd html 4.0 transitional//en\"&gt;");
168            writer.println("&lt;head&gt;&lt;title&gt;JSP Chat&lt;/title&gt;&lt;/head&gt;&lt;body bgcolor=\"#FFFFFF\"&gt;");
169            writer.flush();
170            synchronized(connections) {
171                connections.add(response);
172            }
173        } else if (event.getEventType() == CometEvent.EventType.ERROR) {
174            log("Error for session: " + request.getSession(true).getId());
175            synchronized(connections) {
176                connections.remove(response);
177            }
178            event.close();
179        } else if (event.getEventType() == CometEvent.EventType.END) {
180            log("End for session: " + request.getSession(true).getId());
181            synchronized(connections) {
182                connections.remove(response);
183            }
184            PrintWriter writer = response.getWriter();
185            writer.println("&lt;/body&gt;&lt;/html&gt;");
186            event.close();
187        } else if (event.getEventType() == CometEvent.EventType.READ) {
188            InputStream is = request.getInputStream();
189            byte[] buf = new byte[512];
190            do {
191                int n = is.read(buf); //can throw an IOException
192                if (n &gt; 0) {
193                    log("Read " + n + " bytes: " + new String(buf, 0, n)
194                            + " for session: " + request.getSession(true).getId());
195                } else if (n &lt; 0) {
196                    error(event, request, response);
197                    return;
198                }
199            } while (is.available() &gt; 0);
200        }
201    }
202
203    public class MessageSender implements Runnable {
204
205        protected boolean running = true;
206        protected ArrayList&lt;String&gt; messages = new ArrayList&lt;String&gt;();
207       
208        public MessageSender() {
209        }
210       
211        public void stop() {
212            running = false;
213        }
214
215        /**
216         * Add message for sending.
217         */
218        public void send(String user, String message) {
219            synchronized (messages) {
220                messages.add("[" + user + "]: " + message);
221                messages.notify();
222            }
223        }
224
225        public void run() {
226
227            while (running) {
228
229                if (messages.size() == 0) {
230                    try {
231                        synchronized (messages) {
232                            messages.wait();
233                        }
234                    } catch (InterruptedException e) {
235                        // Ignore
236                    }
237                }
238
239                synchronized (connections) {
240                    String[] pendingMessages = null;
241                    synchronized (messages) {
242                        pendingMessages = messages.toArray(new String[0]);
243                        messages.clear();
244                    }
245                    // Send any pending message on all the open connections
246                    for (int i = 0; i &lt; connections.size(); i++) {
247                        try {
248                            PrintWriter writer = connections.get(i).getWriter();
249                            for (int j = 0; j &lt; pendingMessages.length; j++) {
250                                writer.println(pendingMessages[j] + "&lt;br&gt;");
251                            }
252                            writer.flush();
253                        } catch (IOException e) {
254                            log("IOExeption sending message", e);
255                        }
256                    }
257                }
258
259            }
260
261        }
262
263    }
264
265}
266  </pre></td><td width="1" bgcolor="#023264"><img border="0" hspace="0" vspace="0" height="1" width="1" src="./../images/void.gif"></td></tr><tr><td height="1" width="1" bgcolor="#023264"><img border="0" hspace="0" vspace="0" height="1" width="1" src="./../images/void.gif"></td><td height="1" bgcolor="#023264"><img border="0" hspace="0" vspace="0" height="1" width="1" src="./../images/void.gif"></td><td height="1" width="1" bgcolor="#023264"><img border="0" hspace="0" vspace="0" height="1" width="1" src="./../images/void.gif"></td></tr></table></div>
267 
268  </blockquote></td></tr></table>
269  <table cellpadding="2" cellspacing="0" border="0"><tr><td bgcolor="#828DA6"><font face="arial,helvetica.sanserif" color="#ffffff"><a name="Comet timeouts"><strong>Comet timeouts</strong></a></font></td></tr><tr><td><blockquote>
270    <p>If you are using the NIO connector, you can set individual timeouts for your different comet connections.
271       To set a timeout, simple set a request attribute like the following code shows:
272       <div align="left"><table border="0" cellpadding="0" cellspacing="4"><tr><td height="1" width="1" bgcolor="#023264"><img border="0" hspace="0" vspace="0" height="1" width="1" src="./../images/void.gif"></td><td height="1" bgcolor="#023264"><img border="0" hspace="0" vspace="0" height="1" width="1" src="./../images/void.gif"></td><td height="1" width="1" bgcolor="#023264"><img border="0" hspace="0" vspace="0" height="1" width="1" src="./../images/void.gif"></td></tr><tr><td width="1" bgcolor="#023264"><img border="0" hspace="0" vspace="0" height="1" width="1" src="./../images/void.gif"></td><td height="1" bgcolor="#ffffff"><pre>CometEvent event.... event.setTimeout(30*1000);</pre></td><td width="1" bgcolor="#023264"><img border="0" hspace="0" vspace="0" height="1" width="1" src="./../images/void.gif"></td></tr><tr><td height="1" width="1" bgcolor="#023264"><img border="0" hspace="0" vspace="0" height="1" width="1" src="./../images/void.gif"></td><td height="1" bgcolor="#023264"><img border="0" hspace="0" vspace="0" height="1" width="1" src="./../images/void.gif"></td><td height="1" width="1" bgcolor="#023264"><img border="0" hspace="0" vspace="0" height="1" width="1" src="./../images/void.gif"></td></tr></table></div> or
273       <div align="left"><table border="0" cellpadding="0" cellspacing="4"><tr><td height="1" width="1" bgcolor="#023264"><img border="0" hspace="0" vspace="0" height="1" width="1" src="./../images/void.gif"></td><td height="1" bgcolor="#023264"><img border="0" hspace="0" vspace="0" height="1" width="1" src="./../images/void.gif"></td><td height="1" width="1" bgcolor="#023264"><img border="0" hspace="0" vspace="0" height="1" width="1" src="./../images/void.gif"></td></tr><tr><td width="1" bgcolor="#023264"><img border="0" hspace="0" vspace="0" height="1" width="1" src="./../images/void.gif"></td><td height="1" bgcolor="#ffffff"><pre>event.getHttpServletRequest().setAttribute("org.apache.tomcat.comet.timeout", new Integer(30 * 1000));</pre></td><td width="1" bgcolor="#023264"><img border="0" hspace="0" vspace="0" height="1" width="1" src="./../images/void.gif"></td></tr><tr><td height="1" width="1" bgcolor="#023264"><img border="0" hspace="0" vspace="0" height="1" width="1" src="./../images/void.gif"></td><td height="1" bgcolor="#023264"><img border="0" hspace="0" vspace="0" height="1" width="1" src="./../images/void.gif"></td><td height="1" width="1" bgcolor="#023264"><img border="0" hspace="0" vspace="0" height="1" width="1" src="./../images/void.gif"></td></tr></table></div>
274       This sets the timeout to 30 seconds.
275       Important note, in order to set this timeout, it has to be done on the <code>BEGIN</code> event.
276       The default value is <code>soTimeout</code>
277    </p>
278    <p>If you are using the APR connector, all Comet connections will have the same timeout value. It is <code>soTimeout*50</code>
279    </p>
280  </blockquote></td></tr></table>
281
282  </blockquote></td></tr></table><table cellpadding="2" cellspacing="0" border="0"><tr><td bgcolor="#525D76"><font face="arial,helvetica.sanserif" color="#ffffff"><a name="Asynchronous writes"><strong>Asynchronous writes</strong></a></font></td></tr><tr><td><blockquote>
283
284  <p>
285    When APR or NIO is enabled, Tomcat supports using sendfile to send large static files.
286    These writes, as soon as the system load increases, will be performed
287    asynchronously in the most efficient way. Instead of sending a large response using
288    blocking writes, it is possible to write content to a static file, and write it
289    using a sendfile code. A caching valve could take advantage of this to cache the
290    response data in a file rather than store it in memory. Sendfile support is
291    available if the request attribute <code>org.apache.tomcat.sendfile.support</code>
292    is set to <code>Boolean.TRUE</code>.
293  </p>
294 
295  <p>
296    Any servlet can instruct Tomcat to perform a sendfile call by setting the appropriate
297    request attributes. It is also necessary to correctly set the content length
298    for the response. When using sendfile, it is best to ensure that neither the
299    request or response have been wrapped, since as the response body will be sent later
300    by the connector itself, it cannot be filtered. Other than setting the 3 needed
301    request attributes, the servlet should not send any response data, but it may use
302    any method which will result in modifying the response header (like setting cookies).
303  </p>
304 
305  <ul>
306  <li>org.apache.tomcat.sendfile.filename: Canonical filename of the file which will be sent as
307      a String</li>
308  <li>org.apache.tomcat.sendfile.start: Start offset as a Long</li>
309  <li>org.apache.tomcat.sendfile.end: End offset as a Long</li>
310  </ul>
311
312  </blockquote></td></tr></table></td></tr><!--FOOTER SEPARATOR--><tr><td colspan="2"><hr size="1" noshade></td></tr><!--PAGE FOOTER--><tr><td colspan="2"><div align="center"><font size="-1" color="#525D76"><em>
313        Copyright &copy; 1999-2008, Apache Software Foundation
314        </em></font></div></td></tr></table></body></html>
Note: See TracBrowser for help on using the repository browser.