Start working on async, fairly similar to comet but much more convulated.
authorfhanik <fhanik@13f79535-47bb-0310-9956-ffa450edef68>
Wed, 15 Jul 2009 00:33:14 +0000 (00:33 +0000)
committerfhanik <fhanik@13f79535-47bb-0310-9956-ffa450edef68>
Wed, 15 Jul 2009 00:33:14 +0000 (00:33 +0000)
I'm gonna do checkins in fairly small chunks so folks can tag along and help out. Instead of doing one giant checkin

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

java/org/apache/catalina/connector/AsyncContextImpl.java [new file with mode: 0644]
java/org/apache/catalina/connector/AsyncListenerWrapper.java [new file with mode: 0644]
java/org/apache/catalina/connector/CoyoteAdapter.java
java/org/apache/catalina/connector/Request.java
java/org/apache/catalina/deploy/FilterDef.java
java/org/apache/catalina/startup/WebRuleSet.java
java/org/apache/coyote/ActionCode.java
java/org/apache/coyote/http11/Http11AprProcessor.java
java/org/apache/coyote/http11/Http11NioProcessor.java
java/org/apache/coyote/http11/Http11Processor.java

diff --git a/java/org/apache/catalina/connector/AsyncContextImpl.java b/java/org/apache/catalina/connector/AsyncContextImpl.java
new file mode 100644 (file)
index 0000000..06f843a
--- /dev/null
@@ -0,0 +1,161 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF 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.
+ */
+package org.apache.catalina.connector;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.servlet.AsyncContext;
+import javax.servlet.AsyncListener;
+import javax.servlet.ServletContext;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+
+import org.apache.juli.logging.Log;
+import org.apache.juli.logging.LogFactory;
+/**
+ * 
+ * @author fhanik
+ *
+ */
+public class AsyncContextImpl implements AsyncContext {
+    protected static Log log = LogFactory.getLog(AsyncContextImpl.class);
+    
+    private boolean started = false;
+    private ServletRequest servletRequest = null;
+    private ServletResponse servletResponse = null;
+    private List<AsyncListenerWrapper> listeners = new ArrayList<AsyncListenerWrapper>();
+    private boolean hasOriginalRequestAndResponse = true;
+    
+    public AsyncContextImpl() {
+        //TODO SERVLET3 - async
+    }
+
+    @Override
+    public void complete() {
+        // TODO SERVLET3 - async
+        
+        for (AsyncListenerWrapper wrapper : listeners) {
+            try {
+                wrapper.fireOnComplete();
+            }catch (IOException x) {
+                //how does this propagate, or should it?
+               //TODO SERVLET3 - async 
+                log.error("",x);
+            }
+        }
+
+    }
+
+    @Override
+    public void dispatch() {
+        // TODO SERVLET3 - async
+
+    }
+
+    @Override
+    public void dispatch(String path) {
+        // TODO SERVLET3 - async
+
+    }
+
+    @Override
+    public void dispatch(ServletContext context, String path) {
+        // TODO SERVLET3 - async
+
+    }
+
+    @Override
+    public ServletRequest getRequest() {
+        return getServletRequest();
+    }
+
+    @Override
+    public ServletResponse getResponse() {
+        return getServletResponse();
+    }
+
+    @Override
+    public void start(Runnable run) {
+        // TODO SERVLET3 - async
+
+    }
+    
+    public void addAsyncListener(AsyncListener listener) {
+        AsyncListenerWrapper wrapper = new AsyncListenerWrapper();
+        wrapper.setListener(listener);
+        wrapper.setServletRequest(getServletRequest());
+        wrapper.setServletResponse(getServletResponse());
+        listeners.add(wrapper);
+    }
+
+    public void addAsyncListener(AsyncListener listener, ServletRequest servletRequest, ServletResponse servletResponse) {
+        AsyncListenerWrapper wrapper = new AsyncListenerWrapper();
+        wrapper.setListener(listener);
+        wrapper.setServletRequest(servletRequest);
+        wrapper.setServletResponse(servletResponse);
+        listeners.add(wrapper);
+    }
+    
+    
+    protected void recycle() {
+        started = false;
+        servletRequest = null;
+        servletResponse = null;
+        listeners.clear();
+        hasOriginalRequestAndResponse = true;
+    }
+
+    public boolean isStarted() {
+        return started;
+    }
+
+    public void setStarted(boolean started) {
+        this.started = started;
+    }
+
+    public ServletRequest getServletRequest() {
+        return servletRequest;
+    }
+
+    public void setServletRequest(ServletRequest servletRequest) {
+        this.servletRequest = servletRequest;
+    }
+
+    public ServletResponse getServletResponse() {
+        return servletResponse;
+    }
+
+    public void setServletResponse(ServletResponse servletResponse) {
+        this.servletResponse = servletResponse;
+    }
+
+    @Override
+    public boolean hasOriginalRequestAndResponse() {
+        return hasOriginalRequestAndResponse;
+    }
+
+    public void setHasOriginalRequestAndResponse(boolean hasOriginalRequestAndResponse) {
+        this.hasOriginalRequestAndResponse = hasOriginalRequestAndResponse;
+    }
+    
+    
+    
+    
+
+}
diff --git a/java/org/apache/catalina/connector/AsyncListenerWrapper.java b/java/org/apache/catalina/connector/AsyncListenerWrapper.java
new file mode 100644 (file)
index 0000000..ffdad57
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one or more
+* contributor license agreements.  See the NOTICE file distributed with
+* this work for additional information regarding copyright ownership.
+* The ASF 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.
+*/
+package org.apache.catalina.connector;
+
+import java.io.IOException;
+
+import javax.servlet.AsyncListener;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+/**
+ * TODO SERVLET 3 - async 
+ * @author fhanik
+ *
+ */
+public class AsyncListenerWrapper {
+
+    private AsyncListener listener = null;
+    private ServletRequest servletRequest = null;
+    private ServletResponse servletResponse = null;
+    
+    public void fireOnComplete() throws IOException {
+        // TODO SERVLET 3 - async 
+
+    }
+
+
+    public void fireOnTimeout() throws IOException {
+        // TODO SERVLET 3 - async 
+
+    }
+
+    public ServletRequest getServletRequest() {
+        return servletRequest;
+    }
+
+    public void setServletRequest(ServletRequest servletRequest) {
+        this.servletRequest = servletRequest;
+    }
+
+    public ServletResponse getServletResponse() {
+        return servletResponse;
+    }
+
+    public void setServletResponse(ServletResponse servletResponse) {
+        this.servletResponse = servletResponse;
+    }
+
+    public AsyncListener getListener() {
+        return listener;
+    }
+
+    public void setListener(AsyncListener listener) {
+        this.listener = listener;
+    }
+    
+    
+
+}
index 34a74ee..9258e2f 100644 (file)
@@ -319,7 +319,10 @@ public class CoyoteAdapter
 
             }
 
-            if (!comet) {
+            if (request.isAsyncStarted()) {
+                //TODO SERVLET3 - async
+                res.action(ActionCode.ACTION_ASYNC_START, request.getAsyncContext());
+            } else if (!comet) {
                 response.finishResponse();
                 req.action(ActionCode.ACTION_POST_REQUEST , null);
             }
index 31ee397..f667b64 100644 (file)
@@ -23,6 +23,7 @@ import java.io.InputStream;
 import java.io.IOException;
 import java.io.BufferedReader;
 import java.io.UnsupportedEncodingException;
+import java.nio.channels.IllegalSelectorException;
 import java.security.Principal;
 import java.text.SimpleDateFormat;
 import java.util.ArrayList;
@@ -387,10 +388,29 @@ public class Request
      * Local address
      */
     protected String localName = null;
-
+    
+    /**
+     * asyncSupported
+     */
+    protected boolean asyncSupported = true;
+    
+    /**
+     * AsyncContext 
+     */
+    protected AsyncContextImpl asyncContext = null;
+    
+    /**
+     * async timeout
+     */
+    protected long asyncTimeout = 0;
 
     // --------------------------------------------------------- Public Methods
 
+    
+
+    public void setAsyncSupported(boolean asyncSupported) {
+        this.asyncSupported = asyncSupported;
+    }
 
     /**
      * Release all object references, and initialize instance variables, in
@@ -464,6 +484,9 @@ public class Request
                 reader = null;
             }
         }
+        
+        asyncSupported = true;
+        if (asyncContext!=null) asyncContext.recycle();
 
     }
 
@@ -1436,51 +1459,69 @@ public class Request
      }
 
     public AsyncContext startAsync() {
-        // TODO SERVLET3
-        return null;
+        // TODO SERVLET3 - async
+        if (!isAsyncSupported()) throw new IllegalStateException("Not supported.");
+        if (asyncContext==null) asyncContext = new AsyncContextImpl();
+        else if (asyncContext.isStarted()) throw new IllegalStateException("Already started.");
+        asyncContext.setServletRequest(getRequest());
+        asyncContext.setServletResponse(response.getResponse());
+        asyncContext.setStarted(true);
+        return asyncContext;
     }
 
-    public AsyncContext startAsync(ServletRequest request,
-            ServletResponse response) {
-        // TODO SERVLET3
-        return null;
+    public AsyncContext startAsync(ServletRequest request, ServletResponse response) {
+        startAsync();
+        asyncContext.setServletRequest(request);
+        asyncContext.setServletResponse(response);
+        asyncContext.setHasOriginalRequestAndResponse(request==getRequest() && response==getResponse());
+        return asyncContext;
     }
 
     public boolean isAsyncStarted() {
-        // TODO SERVLET3
-        return false;
+        if (asyncContext==null) return false;
+        else return asyncContext.isStarted();
     }
 
     public boolean isAsyncSupported() {
-        // TODO SERVLET3
-        return false;
+        // TODO SERVLET3 - async
+        return this.asyncSupported;
     }
 
     public AsyncContext getAsyncContext() {
-        // TODO SERVLET3
-        return null;
+        // TODO SERVLET3 - async
+        return this.asyncContext;
     }
 
     public void addAsyncListener(AsyncListener listener) {
-        // TODO SERVLET3
+        // TODO SERVLET3 - async
+        if (isAsyncSupported() && isAsyncStarted()) {
+            this.asyncContext.addAsyncListener(listener);
+        } else {
+            throw new IllegalStateException("Async [Supported:"+isAsyncSupported()+"; Started:"+isAsyncStarted()+"]");
+        }
     }
 
-    public void addAsyncListener(AsyncListener listener,
-            ServletRequest servletRequest, ServletResponse servletResponse) {
-        // TODO SERVLET3
+    public void addAsyncListener(AsyncListener listener, ServletRequest servletRequest, ServletResponse servletResponse) {
+        // TODO SERVLET3 - async
+        if (isAsyncSupported() && isAsyncStarted()) {
+            this.asyncContext.addAsyncListener(listener,servletRequest,servletResponse);
+        } else {
+            throw new IllegalStateException("Async [Supported:"+isAsyncSupported()+"; Started:"+isAsyncStarted()+"]");
+        }
     }
 
     public void setAsyncTimeout(long timeout) {
-        // TODO SERVLET3
+        // TODO SERVLET3 - async
+        this.asyncTimeout = timeout;
     }
     
     public long getAsyncTimeout() {
-        // TODO SERVLET3
-        return 0;
+        // TODO SERVLET3 - async
+        return asyncTimeout;
     }
     
     public DispatcherType getDispatcherType() {
-        // TODO SERVLET3
+        // TODO SERVLET3 - dispatcher
         return null;
     }
 
@@ -2241,26 +2282,26 @@ public class Request
     }
     
     public boolean authenticate(HttpServletResponse response) throws IOException {
-        // TODO Servlet 3
+        // TODO Servlet 3 - authentication
         return false;
     }
     
     public void login(String username, String password)
     throws ServletException {
-        // TODO Servlet 3
+        // TODO Servlet 3 - authentication
     }
     
     public void logout() throws ServletException {
-        // TODO Servlet 3
+        // TODO Servlet 3 - authentication
     }
     
     public Iterable<Part> getParts() {
-        // TODO Servlet 3
+        // TODO Servlet 3 - authentication
         return null;
     }
     
     public Part getPart(String name) throws IllegalArgumentException {
-        // TODO Servlet 3.0
+        // TODO Servlet 3.0 - file upload
         return null;
     }
 
index fa66c18..f0d1d19 100644 (file)
@@ -134,6 +134,16 @@ public class FilterDef implements Serializable {
     public void setSmallIcon(String smallIcon) {
         this.smallIcon = smallIcon;
     }
+    
+    private boolean asyncSupported = false;
+    
+    public boolean isAsyncSupported() {
+        return asyncSupported;
+    }
+    
+    public void setAsyncSupported(boolean asyncSupported) {
+        this.asyncSupported = asyncSupported;
+    }
 
 
     // --------------------------------------------------------- Public Methods
index 9bc7d55..b4b9457 100644 (file)
@@ -171,6 +171,11 @@ public class WebRuleSet extends RuleSetBase {
                                "setLargeIcon", 0);
         digester.addCallMethod(prefix + "web-app/filter/small-icon",
                                "setSmallIcon", 0);
+        
+        //spec right now only has an annotation, not XML but we will add it
+        //TODO SERVLET3 - async 
+        digester.addCallMethod(prefix + "web-app/filter/asyncSupported",
+                "setAsyncSupported", 0);
 
         digester.addCallMethod(prefix + "web-app/filter/init-param",
                                "addInitParameter", 2);
index ac2e0fc..7219483 100644 (file)
@@ -161,6 +161,21 @@ public final class ActionCode {
      */
     public static final ActionCode ACTION_COMET_SETTIMEOUT = new ActionCode(25);
     
+    /**
+     * Callback for an async request
+     */
+    public static final ActionCode ACTION_ASYNC_START = new ActionCode(26);
+    
+    /**
+     * Callback for an async call to {@link javax.servlet.AsyncContext#complete()}
+     */
+    public static final ActionCode ACTION_ASYNC_COMPLETE = new ActionCode(27);
+    /**
+     * Callback for an async call to {@link javax.servlet.ServletRequest#setAsyncTimeout(long)}
+     */
+    public static final ActionCode ACTION_ASYNC_SETTIMEOUT = new ActionCode(28);
+    
+    
     // ----------------------------------------------------------- Constructors
     int code;
 
index 9920455..9fe459c 100644 (file)
@@ -1201,7 +1201,14 @@ public class Http11AprProcessor implements ActionHook {
             //no op
         } else if (actionCode == ActionCode.ACTION_COMET_SETTIMEOUT) {
             //no op
+        } else if (actionCode == ActionCode.ACTION_ASYNC_START) {
+            //TODO SERVLET3 - async
+        } else if (actionCode == ActionCode.ACTION_ASYNC_COMPLETE) {
+          //TODO SERVLET3 - async
+        } else if (actionCode == ActionCode.ACTION_ASYNC_SETTIMEOUT) {
+          //TODO SERVLET3 - async
         }
+        
 
     }
 
index e68d804..8305409 100644 (file)
@@ -1238,6 +1238,12 @@ public class Http11NioProcessor implements ActionHook {
             RequestInfo rp = request.getRequestProcessor();
             if ( rp.getStage() != org.apache.coyote.Constants.STAGE_SERVICE ) //async handling
                 attach.setTimeout(timeout);
+        } else if (actionCode == ActionCode.ACTION_ASYNC_START) {
+            //TODO SERVLET3 - async
+        } else if (actionCode == ActionCode.ACTION_ASYNC_COMPLETE) {
+          //TODO SERVLET3 - async
+        } else if (actionCode == ActionCode.ACTION_ASYNC_SETTIMEOUT) {
+          //TODO SERVLET3 - async
         }
     }
 
index 7d54c48..f70f03f 100644 (file)
@@ -1106,6 +1106,12 @@ public class Http11Processor implements ActionHook {
             InternalInputBuffer internalBuffer = (InternalInputBuffer)
                 request.getInputBuffer();
             internalBuffer.addActiveFilter(savedBody);
+        } else if (actionCode == ActionCode.ACTION_ASYNC_START) {
+            //TODO SERVLET3 - async
+        } else if (actionCode == ActionCode.ACTION_ASYNC_COMPLETE) {
+          //TODO SERVLET3 - async
+        } else if (actionCode == ActionCode.ACTION_ASYNC_SETTIMEOUT) {
+          //TODO SERVLET3 - async
         }
 
     }