From 770c3908e7d89b179b08dcf07475369a2f1d879d Mon Sep 17 00:00:00 2001 From: remm Date: Tue, 3 Oct 2006 00:17:20 +0000 Subject: [PATCH] - First pass at docs. git-svn-id: https://svn.apache.org/repos/asf/tomcat/tc6.0.x/trunk@452281 13f79535-47bb-0310-9956-ffa450edef68 --- webapps/docs/aio.xml | 256 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 256 insertions(+) diff --git a/webapps/docs/aio.xml b/webapps/docs/aio.xml index 4cd00c87d..fe83d3c62 100644 --- a/webapps/docs/aio.xml +++ b/webapps/docs/aio.xml @@ -16,9 +16,265 @@

+ With usage of APR or NIO APIs as the basis of its connectors, Tomcat is + able to provide a number of extensions over the regular blocking IO + as provided with support for the Servlet API.

+
+ +

+ Comet support allows a servlet to process IO aynchronously, recieving + events when data is available for reading on the connection (rather than + always using a blocking read), and writing data back on connections + asychnonously (most likely responding to some event raised from some + other source). +

+ + + +

+ Servlets which implement the org.apache.catalina.CometProcessor + interface will have their event method invoked rather than the usual service + method, according to the event which occurred. The event object gives + access to the usual request and response objects, which may be used in the + usual way. The main difference is that those objects remain valid and fully + functional at any time between processing of the BEGIN event until processing + an END or ERROR event. + The following event types exist: +

+ +
    +
  • EventType.BEGIN: will be called at the beginning + of the processing of the connection. It can be used to initialize any relevant + fields using the request and response objects. Between the end of the processing + of this event, and the beginning of the processing of the end or error events, + it is possible to use the response object to write data on the open connection. + Note that the response object and depedent OutputStream and Writer are still + not synchronized, so when they are accessed by multiple threads, + synchronization is mandatory. After processing the initial event, the request + is considered to be committed.
  • +
  • EventType.READ: This indicates that input data is available, and that one read can be made + without blocking. The available and ready methods of the InputStream or + Reader may be used to determine if there is a risk of blocking: the servlet + should read while data is reported available, and can make one additional read + without blocking. When encountering a read error or an EOF, the servlet MUST + report it by either returning false or throwing an exception such as an + IOException. This will cause the error event to be invoked, and the connection + will be closed. It is not allowed to attempt reading data from the request object + outside of the execution of this method.
  • +
  • EventType.END: End may be called to end the processing of the request. Fields that have + been initialized in the begin method should be reset. After this event has + been processed, the request and response objects, as well as all their dependent + objects will be recycled and used to process other requests.
  • +
  • EventType.ERROR: Error will be called by the container in the case where an IO exception + or a similar unrecoverable error occurs on the connection. Fields that have + been initialized in the begin method should be reset. After this event has + been processed, the request and response objects, as well as all their dependent + objects will be recycled and used to process other requests.
  • +
+ +

+ As described above, the typical lifecycle of a Comet request will consist in a series of + events such as: BEGIN -> READ -> READ -> READ -> ERROR/TIMEOUT. At any time, the servlet + may end processing of the request by using the close method of the event object. +

+ +
+ + + +

+ Similar to regular filters, a filter chain is invoked when comet events are processed. + These filters should implement the CometFilter interface (which works in the same way as + the regular Filter interface), and should be declared and mapped in the deployment + descriptor in the same way as a regular filter. The filter chain when processing an event + will only include filters which match all the usual mapping rules, and also implement + the CometFiler interface. +

+ +
+ + + +

+ The following pseudo code servlet implments asynchronous chat functionality using the API + described above: +

+ + +public class ChatServlet + extends HttpServlet implements CometProcessor { + + protected ArrayList<HttpServletResponse> connections = + new ArrayList<HttpServletResponse>(); + protected MessageSender messageSender = null; + + public void init() throws ServletException { + messageSender = new MessageSender(); + Thread messageSenderThread = + new Thread(messageSender, "MessageSender[" + getServletContext().getContextPath() + "]"); + messageSenderThread.setDaemon(true); + messageSenderThread.start(); + } + + public void destroy() { + connections.clear(); + messageSender.stop(); + messageSender = null; + } + + /** + * Process the given Comet event. + * + * @param event The Comet event that will be processed + * @throws IOException + * @throws ServletException + */ + public void event(CometEvent event) + throws IOException, ServletException { + HttpServletRequest request = event.getHttpServletRequest(); + HttpServletResponse response = event.getHttpServletResponse(); + if (event.getEventType() == CometEvent.EventType.BEGIN) { + log("Begin for session: " + request.getSession(true).getId()); + PrintWriter writer = response.getWriter(); + writer.println("<!doctype html public \"-//w3c//dtd html 4.0 transitional//en\">"); + writer.println("<head><title>JSP Chat</title></head><body bgcolor=\"#FFFFFF\">"); + writer.flush(); + synchronized(connections) { + connections.add(response); + } + } else if (event.getEventType() == CometEvent.EventType.ERROR) { + log("Error for session: " + request.getSession(true).getId()); + synchronized(connections) { + connections.remove(response); + } + event.close(); + } else if (event.getEventType() == CometEvent.EventType.END) { + log("End for session: " + request.getSession(true).getId()); + synchronized(connections) { + connections.remove(response); + } + PrintWriter writer = response.getWriter(); + writer.println("</body></html>"); + event.close(); + } else if (event.getEventType() == CometEvent.EventType.READ) { + InputStream is = request.getInputStream(); + byte[] buf = new byte[512]; + do { + int n = is.read(buf); + if (n > 0) { + log("Read " + n + " bytes: " + new String(buf, 0, n) + + " for session: " + request.getSession(true).getId()); + } else if (n < 0) { + error(event, request, response); + return; + } + } while (is.available() > 0); + } + } + + public class MessageSender implements Runnable { + + protected boolean running = true; + protected ArrayList<String> messages = new ArrayList<String>(); + + public MessageSender() { + } + + public void stop() { + running = false; + } + + /** + * Add message for sending. + */ + public void send(String user, String message) { + synchronized (messages) { + messages.add("[" + user + "]: " + message); + messages.notify(); + } + } + + public void run() { + + while (running) { + + if (messages.size() == 0) { + try { + synchronized (messages) { + messages.wait(); + } + } catch (InterruptedException e) { + // Ignore + } + } + + synchronized (connections) { + String[] pendingMessages = null; + synchronized (messages) { + pendingMessages = messages.toArray(new String[0]); + messages.clear(); + } + // Send any pending message on all the open connections + for (int i = 0; i < connections.size(); i++) { + try { + PrintWriter writer = connections.get(i).getWriter(); + for (int j = 0; j < pendingMessages.length; j++) { + writer.println(pendingMessages[j] + "<br>"); + } + writer.flush(); + } catch (IOException e) { + log("IOExeption sending message", e); + } + } + } + + } + + } + + } + +} + + +
+ +
+ +
+ +

+ When APR is enabled, Tomcat supports using sendfile to send large static files. + These writes, as soon as the system load increases, will be performed + asynchronously in the most efficient way. Instead of sending a large response using + blocking writes, it is possible to write content to a static file, and write it + using a sendfile code. A caching valve could take advantage of this to cache the + response data in a file rather than store it in memory. Sendfile support is + available if the request attribute org.apache.tomcat.sendfile.support + is set to Boolean.TRUE. +

+ +

+ Any servlet can instruct Tomcat to perform a sendfile call by setting the appropriate + response attributes. When using sendfile, it is best to ensure that neither the + request or response have been wrapped, since as the response body will be sent later + by the connector itself, it cannot be filtered. Other than setting the 3 needed + response attributes, the servlet should not send any response data, but it may use + any method which will result in modifying the response header (like setting cookies). +

+ + + +
+ -- 2.11.0