- Ok, it seems to work at least a little bit (hopefully, nobody tried it before this...
authorremm <remm@13f79535-47bb-0310-9956-ffa450edef68>
Thu, 18 May 2006 18:29:07 +0000 (18:29 +0000)
committerremm <remm@13f79535-47bb-0310-9956-ffa450edef68>
Thu, 18 May 2006 18:29:07 +0000 (18:29 +0000)
  changes are fairly limited.
- In the end, I prefer adding a new method in Adapter, although it is easy to change back.
- I'll try to add the examples webapp back, and add the obligatory chat servlet (so lame ...).

git-svn-id: https://svn.apache.org/repos/asf/tomcat/tc6.0.x/trunk@407605 13f79535-47bb-0310-9956-ffa450edef68

java/org/apache/catalina/CometProcessor.java
java/org/apache/catalina/connector/CoyoteAdapter.java
java/org/apache/catalina/servlets/CometServlet.java
java/org/apache/coyote/Adapter.java
java/org/apache/coyote/http11/Http11AprProcessor.java
java/org/apache/coyote/http11/Http11AprProtocol.java
java/org/apache/tomcat/util/net/AprEndpoint.java

index 1c219dd..ded67f9 100644 (file)
@@ -1,3 +1,20 @@
+/*
+ * Copyright 2006 The Apache Software Foundation.
+ * 
+ * Licensed 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.
+ */
+
+
 package org.apache.catalina;
 
 import java.io.IOException;
@@ -8,13 +25,56 @@ import javax.servlet.http.HttpServletResponse;
 
 public interface CometProcessor {
 
+    /**
+     * Begin will be called by the main service method of the servlet at the beginning 
+     * of the processing of the connection. It can be used to initialize any relevant 
+     * fields using the request and response objects.
+     * 
+     * @param request
+     * @param response
+     * @throws IOException
+     * @throws ServletException
+     */
     public void begin(HttpServletRequest request, HttpServletResponse response)
         throws IOException, ServletException;
+
+    /**
+     * End may be called to end the processing of the request. Fields that have
+     * been initialized in the begin method should be reset.
+     * 
+     * @param request
+     * @param response
+     * @throws IOException
+     * @throws ServletException
+     */
     public void end(HttpServletRequest request, HttpServletResponse response)
         throws IOException, ServletException;
 
+    /**
+     * 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.
+     * 
+     * @param request
+     * @param response
+     * @throws IOException
+     * @throws ServletException
+     */
     public void error(HttpServletRequest request, HttpServletResponse response)
         throws IOException, ServletException;
+    
+    /**
+     * 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.
+     * 
+     * @param request
+     * @param response
+     * @throws IOException
+     * @throws ServletException
+     */
     public void read(HttpServletRequest request, HttpServletResponse response)
         throws IOException, ServletException;
 
index ace2985..85779f7 100644 (file)
@@ -103,6 +103,56 @@ public class CoyoteAdapter
 \r
     // -------------------------------------------------------- Adapter Methods\r
 \r
+    \r
+    /**\r
+     * Event method.\r
+     * \r
+     * @return false to indicate an error, expected or not\r
+     */\r
+    public boolean event(org.apache.coyote.Request req, \r
+            org.apache.coyote.Response res, boolean error) {\r
+\r
+        Request request = (Request) req.getNote(ADAPTER_NOTES);\r
+        Response response = (Response) res.getNote(ADAPTER_NOTES);\r
+\r
+        if (request.getWrapper() != null) {\r
+            CometProcessor servlet = null;\r
+            try {\r
+                servlet = (CometProcessor) request.getWrapper().allocate();\r
+            } catch (Throwable t) {\r
+                log.error(sm.getString("coyoteAdapter.service"), t);\r
+                request.removeAttribute("org.apache.tomcat.comet");\r
+                return false;\r
+            }\r
+            try {\r
+                if (error) {\r
+                    servlet.error(request.getRequest(), response.getResponse());\r
+                } else {\r
+                    servlet.read(request.getRequest(), response.getResponse());\r
+                }\r
+                return (!error);\r
+            } catch (Throwable t) {\r
+                if (!(t instanceof IOException)) {\r
+                    log.error(sm.getString("coyoteAdapter.service"), t);\r
+                }\r
+                request.removeAttribute("org.apache.tomcat.comet");\r
+                try {\r
+                    servlet.error(request.getRequest(), response.getResponse());\r
+                } catch (Throwable th) {\r
+                    log.error(sm.getString("coyoteAdapter.service"), th);\r
+                }\r
+                return false;\r
+            } finally {\r
+                // Recycle the wrapper request and response\r
+                if (request.getAttribute("org.apache.tomcat.comet") == null) {\r
+                    request.recycle();\r
+                    response.recycle();\r
+                }\r
+            }\r
+        }\r
+        return true;\r
+    }\r
+    \r
 \r
     /**\r
      * Service method.\r
@@ -136,29 +186,6 @@ public class CoyoteAdapter
 \r
         }\r
 \r
-        // Comet processing\r
-        if (request.getWrapper() != null \r
-                && request.getWrapper() instanceof CometProcessor) {\r
-            try {\r
-                if (request.getAttribute("org.apache.tomcat.comet.error") != null) {\r
-                    ((CometProcessor) request.getWrapper()).error(request.getRequest(), response.getResponse());\r
-                } else {\r
-                    ((CometProcessor) request.getWrapper()).read(request.getRequest(), response.getResponse());\r
-                }\r
-            } catch (IOException e) {\r
-                ;\r
-            } catch (Throwable t) {\r
-                log.error(sm.getString("coyoteAdapter.service"), t);\r
-            } finally {\r
-                // Recycle the wrapper request and response\r
-                if (request.getAttribute("org.apache.tomcat.comet") == null) {\r
-                    request.recycle();\r
-                    response.recycle();\r
-                }\r
-            }\r
-            return;\r
-        }\r
-        \r
         if (connector.getXpoweredBy()) {\r
             response.addHeader("X-Powered-By", "Servlet/2.5");\r
         }\r
@@ -174,9 +201,8 @@ public class CoyoteAdapter
                 connector.getContainer().getPipeline().getFirst().invoke(request, response);\r
             }\r
 \r
-            if (request.getAttribute("org.apache.tomcat.comet.support") == Boolean.TRUE \r
-                    && request.getWrapper() instanceof CometProcessor) {\r
-                request.setAttribute("org.apache.tomcat.comet", Boolean.TRUE);\r
+            if (request.getAttribute("org.apache.tomcat.comet") == Boolean.TRUE\r
+                    && request.getWrapper().allocate() instanceof CometProcessor) {\r
                 comet = true;\r
             }\r
 \r
index 066eb4a..7536977 100644 (file)
@@ -21,8 +21,6 @@ package org.apache.catalina.servlets;
 import java.io.IOException;
 
 import javax.servlet.ServletException;
-import javax.servlet.ServletRequest;
-import javax.servlet.ServletResponse;
 import javax.servlet.http.HttpServlet;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
@@ -38,7 +36,7 @@ public abstract class CometServlet
 
     public void begin(HttpServletRequest request, HttpServletResponse response)
         throws IOException, ServletException {
-        
+        request.setAttribute("org.apache.tomcat.comet", Boolean.TRUE);
     }
     
     public void end(HttpServletRequest request, HttpServletResponse response)
index 3aedca1..e5a78a3 100644 (file)
@@ -45,5 +45,7 @@ public interface Adapter {
     public void service(Request req, Response res)\r
        throws Exception;\r
 \r
+    public boolean event(Request req, Response res, boolean error)\r
+    throws Exception;\r
 \r
 }\r
index b6d5194..841e81f 100644 (file)
@@ -743,15 +743,9 @@ public class Http11AprProcessor implements ActionHook {
         \r
         try {\r
             rp.setStage(org.apache.coyote.Constants.STAGE_SERVICE);\r
-            if (error) {\r
-                request.setAttribute("org.apache.tomcat.comet.error", Boolean.TRUE);\r
-            }\r
-            // FIXME: It is also possible to add a new "event" method in the adapter\r
-            // or something similar\r
-            adapter.service(request, response);\r
+            error = !adapter.event(request, response, error);\r
             if (request.getAttribute("org.apache.tomcat.comet") == null) {\r
                 comet = false;\r
-                endpoint.getCometPoller().remove(socket);\r
             }\r
         } catch (InterruptedIOException e) {\r
             error = true;\r
@@ -772,6 +766,7 @@ public class Http11AprProcessor implements ActionHook {
             endpoint.getPoller().add(socket);\r
             return SocketState.OPEN;\r
         } else {\r
+            endpoint.getCometPoller().add(socket);\r
             return SocketState.LONG;\r
         }\r
     }\r
@@ -815,7 +810,7 @@ public class Http11AprProcessor implements ActionHook {
         boolean keptAlive = false;\r
         boolean openSocket = false;\r
 \r
-        while (!error && keepAlive) {\r
+        while (!error && keepAlive && !comet) {\r
 \r
             // Parsing the request header\r
             try {\r
@@ -927,7 +922,6 @@ public class Http11AprProcessor implements ActionHook {
                 recycle();\r
                 return SocketState.CLOSED;\r
             } else {\r
-                endpoint.getCometPoller().add(socket);\r
                 return SocketState.LONG;\r
             }\r
         } else {\r
index dd10203..86d8b0f 100644 (file)
@@ -617,6 +617,7 @@ public class Http11AprProtocol implements ProtocolHandler, MBeanRegistration
 \r
         public SocketState event(long socket, boolean error) {\r
             Http11AprProcessor result = connections.get(socket);\r
+            \r
             SocketState state = SocketState.CLOSED; \r
             if (result != null) {\r
                 boolean recycle = error;\r
@@ -708,10 +709,11 @@ public class Http11AprProtocol implements ProtocolHandler, MBeanRegistration
                     // processor.\r
                     connections.put(socket, processor);\r
                     localProcessor.set(null);\r
+                    proto.ep.getCometPoller().add(socket);\r
                 }\r
                 return state;\r
 \r
-            } catch(java.net.SocketException e) {\r
+            } catch (java.net.SocketException e) {\r
                 // SocketExceptions are normal\r
                 Http11AprProtocol.log.debug\r
                     (sm.getString\r
index 1e2ddf6..82445af 100644 (file)
@@ -796,6 +796,10 @@ public class AprEndpoint {
                 pollers[i].destroy();\r
             }\r
             pollers = null;\r
+            for (int i = 0; i < cometPollers.length; i++) {\r
+                cometPollers[i].destroy();\r
+            }\r
+            cometPollers = null;\r
             if (useSendfile) {\r
                 for (int i = 0; i < sendfiles.length; i++) {\r
                     sendfiles[i].destroy();\r
@@ -1107,8 +1111,6 @@ public class AprEndpoint {
 \r
         protected long[] addS;\r
         protected int addCount = 0;\r
-        protected long[] removeS;\r
-        protected int removeCount = 0;\r
         \r
         protected boolean comet = true;\r
 \r
@@ -1145,10 +1147,6 @@ public class AprEndpoint {
             keepAliveCount = 0;\r
             addS = new long[size];\r
             addCount = 0;\r
-            if (comet) {\r
-                removeS = new long[size];\r
-            }\r
-            removeCount = 0;\r
         }\r
 \r
         /**\r
@@ -1159,15 +1157,9 @@ public class AprEndpoint {
             for (int i = 0; i < addCount; i++) {\r
                 if (comet) {\r
                     processSocket(addS[i], true);\r
+                } else {\r
+                    Socket.destroy(addS[i]);\r
                 }\r
-                Socket.destroy(addS[i]);\r
-            }\r
-            // Close all sockets in the remove queue\r
-            for (int i = 0; i < removeCount; i++) {\r
-                if (comet) {\r
-                    processSocket(removeS[i], true);\r
-                }\r
-                Socket.destroy(removeS[i]);\r
             }\r
             // Close all sockets still in the poller\r
             int rv = Poll.pollset(serverPollset, desc);\r
@@ -1175,14 +1167,14 @@ public class AprEndpoint {
                 for (int n = 0; n < rv; n++) {\r
                     if (comet) {\r
                         processSocket(desc[n*2+1], true);\r
+                    } else {\r
+                        Socket.destroy(desc[n*2+1]);\r
                     }\r
-                    Socket.destroy(desc[n*2+1]);\r
                 }\r
             }\r
             Pool.destroy(pool);\r
             keepAliveCount = 0;\r
             addCount = 0;\r
-            removeCount = 0;\r
         }\r
 \r
         /**\r
@@ -1201,8 +1193,9 @@ public class AprEndpoint {
                     // Can't do anything: close the socket right away\r
                     if (comet) {\r
                         processSocket(socket, true);\r
+                    } else {\r
+                        Socket.destroy(socket);\r
                     }\r
-                    Socket.destroy(socket);\r
                     return;\r
                 }\r
                 addS[addCount] = socket;\r
@@ -1212,30 +1205,6 @@ public class AprEndpoint {
         }\r
 \r
         /**\r
-         * Remove specified socket and associated pool from the poller. The socket will\r
-         * be added to a temporary array, and polled first after a maximum amount\r
-         * of time equal to pollTime (in most cases, latency will be much lower,\r
-         * however). Note that this is automatic, except if the poller is used for\r
-         * comet.\r
-         *\r
-         * @param socket to remove from the poller\r
-         */\r
-        public void remove(long socket) {\r
-            synchronized (this) {\r
-                // Add socket to the list. Newly added sockets will wait\r
-                // at most for pollTime before being polled\r
-                if (removeCount >= removeS.length) {\r
-                    // Normally, it cannot happen ...\r
-                    Socket.destroy(socket);\r
-                    return;\r
-                }\r
-                removeS[removeCount] = socket;\r
-                removeCount++;\r
-                this.notify();\r
-            }\r
-        }\r
-\r
-        /**\r
          * The background thread that listens for incoming TCP/IP connections and\r
          * hands them off to an appropriate processor.\r
          */\r
@@ -1279,26 +1248,18 @@ public class AprEndpoint {
                                     // Can't do anything: close the socket right away\r
                                     if (comet) {\r
                                         processSocket(addS[i], true);\r
+                                    } else {\r
+                                        Socket.destroy(addS[i]);\r
                                     }\r
-                                    Socket.destroy(addS[i]);\r
                                 }\r
                             }\r
                             addCount = 0;\r
                         }\r
                     }\r
-                    // Remove sockets which are waiting to the poller\r
-                    if (removeCount > 0) {\r
-                        synchronized (this) {\r
-                            for (int i = 0; i < removeCount; i++) {\r
-                                int rv = Poll.remove(serverPollset, removeS[i]);\r
-                            }\r
-                            removeCount = 0;\r
-                        }\r
-                    }\r
 \r
                     maintainTime += pollTime;\r
                     // Pool for the specified interval\r
-                    int rv = Poll.poll(serverPollset, pollTime, desc, !comet);\r
+                    int rv = Poll.poll(serverPollset, pollTime, desc, true);\r
                     if (rv > 0) {\r
                         keepAliveCount -= rv;\r
                         for (int n = 0; n < rv; n++) {\r
@@ -1306,13 +1267,13 @@ public class AprEndpoint {
                             if (((desc[n*2] & Poll.APR_POLLHUP) == Poll.APR_POLLHUP)\r
                                     || ((desc[n*2] & Poll.APR_POLLERR) == Poll.APR_POLLERR)\r
                                     || (comet && (!processSocket(desc[n*2+1], false))) \r
-                                    || (!processSocket(desc[n*2+1]))) {\r
+                                    || (!comet && (!processSocket(desc[n*2+1])))) {\r
                                 // Close socket and clear pool\r
                                 if (comet) {\r
                                     processSocket(desc[n*2+1], true);\r
-                                    Poll.remove(serverPollset, desc[n*2+1]);\r
+                                } else {\r
+                                    Socket.destroy(desc[n*2+1]);\r
                                 }\r
-                                Socket.destroy(desc[n*2+1]);\r
                                 continue;\r
                             }\r
                         }\r
@@ -1343,8 +1304,9 @@ public class AprEndpoint {
                                     // FIXME: should really close in case of timeout ?\r
                                     // FIXME: maybe comet should use an extended timeout\r
                                     processSocket(desc[n], true);\r
+                                } else {\r
+                                    Socket.destroy(desc[n]);\r
                                 }\r
-                                Socket.destroy(desc[n]);\r
                             }\r
                         }\r
                     }\r
@@ -1467,7 +1429,7 @@ public class AprEndpoint {
                     // Close socket and pool\r
                     Socket.destroy(socket);\r
                     socket = 0;\r
-                } else if (handler.process(socket) == Handler.SocketState.CLOSED) {\r
+                } else if ((!event) && (handler.process(socket) == Handler.SocketState.CLOSED)) {\r
                     // Close socket and pool\r
                     Socket.destroy(socket);\r
                     socket = 0;\r