From: fhanik Date: Fri, 7 Aug 2009 14:49:19 +0000 (+0000) Subject: Refactor location of AsyncContextImpl to o.a.catalina.core X-Git-Url: https://git.internetallee.de/?a=commitdiff_plain;h=06fded5fa68ca9e5fec772b6ae500d7c92e53c55;p=tomcat7.0 Refactor location of AsyncContextImpl to o.a.catalina.core git-svn-id: https://svn.apache.org/repos/asf/tomcat/trunk@802026 13f79535-47bb-0310-9956-ffa450edef68 --- diff --git a/java/javax/servlet/AsyncContext.java b/java/javax/servlet/AsyncContext.java index b944388cf..200c764c1 100644 --- a/java/javax/servlet/AsyncContext.java +++ b/java/javax/servlet/AsyncContext.java @@ -16,7 +16,7 @@ */ package javax.servlet; -import org.apache.catalina.connector.AsyncContextImpl.AsyncState; +import org.apache.catalina.core.AsyncContextImpl.AsyncState; /** * @since Servlet 3.0 diff --git a/java/javax/servlet/AsyncEvent.java b/java/javax/servlet/AsyncEvent.java index 3012de9af..6ba2f0c74 100644 --- a/java/javax/servlet/AsyncEvent.java +++ b/java/javax/servlet/AsyncEvent.java @@ -25,7 +25,7 @@ public class AsyncEvent { private ServletRequest request; private ServletResponse response; - AsyncEvent(ServletRequest request, ServletResponse response) { + public AsyncEvent(ServletRequest request, ServletResponse response) { this.request = request; this.response = response; } diff --git a/java/org/apache/catalina/connector/AsyncContextImpl.java b/java/org/apache/catalina/connector/AsyncContextImpl.java deleted file mode 100644 index 95909b896..000000000 --- a/java/org/apache/catalina/connector/AsyncContextImpl.java +++ /dev/null @@ -1,342 +0,0 @@ -/* - * 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 java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicReference; - -import javax.servlet.AsyncContext; -import javax.servlet.AsyncListener; -import javax.servlet.DispatcherType; -import javax.servlet.RequestDispatcher; -import javax.servlet.ServletContext; -import javax.servlet.ServletException; -import javax.servlet.ServletRequest; -import javax.servlet.ServletResponse; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -import org.apache.catalina.Context; -import org.apache.catalina.Globals; -import org.apache.coyote.ActionCode; -import org.apache.juli.logging.Log; -import org.apache.juli.logging.LogFactory; -/** - * - * @author fhanik - * - */ -public class AsyncContextImpl implements AsyncContext { - - public static enum AsyncState { - NOT_STARTED, STARTED, DISPATCHING, DISPATCHED, COMPLETING, TIMING_OUT - } - - protected static Log log = LogFactory.getLog(AsyncContextImpl.class); - - private ServletRequest servletRequest = null; - private ServletResponse servletResponse = null; - private List listeners = new ArrayList(); - private boolean hasOriginalRequestAndResponse = true; - private volatile Runnable dispatch = null; - private Context context = null; - private AtomicReference state = new AtomicReference(AsyncState.NOT_STARTED); - private long timeout = -1; - - private Request request; - - public AsyncContextImpl(Request request) { - //TODO SERVLET3 - async - this.request = request; - } - - @Override - public void complete() { - if (state.compareAndSet(AsyncState.STARTED, AsyncState.COMPLETING) || - state.compareAndSet(AsyncState.DISPATCHED, AsyncState.COMPLETING)) { - // TODO SERVLET3 - async - AtomicBoolean dispatched = new AtomicBoolean(false); - request.coyoteRequest.action(ActionCode.ACTION_ASYNC_COMPLETE,dispatched); - if (!dispatched.get()) doInternalComplete(false); - } else { - throw new IllegalStateException("Complete not allowed. Invalid state:"+state.get()); - } - - } - - @Override - public void dispatch() { - HttpServletRequest sr = (HttpServletRequest)getServletRequest(); - String path = sr.getRequestURI(); - String cpath = sr.getContextPath(); - if (cpath.length()>1) path = path.substring(cpath.length()); - dispatch(path); - } - - @Override - public void dispatch(String path) { - dispatch(request.getServletContext(),path); - } - - @Override - public void dispatch(ServletContext context, String path) { - // TODO SERVLET3 - async - if (state.compareAndSet(AsyncState.STARTED, AsyncState.DISPATCHING) || - state.compareAndSet(AsyncState.DISPATCHED, AsyncState.DISPATCHING)) { - - if (request.getAttribute(ASYNC_REQUEST_URI)==null) { - request.setAttribute(ASYNC_REQUEST_URI, request.getRequestURI()); - request.setAttribute(ASYNC_CONTEXT_PATH, request.getContextPath()); - request.setAttribute(ASYNC_SERVLET_PATH, request.getServletPath()); - request.setAttribute(ASYNC_QUERY_STRING, request.getQueryString()); - } - final RequestDispatcher requestDispatcher = context.getRequestDispatcher(path); - final HttpServletRequest servletRequest = (HttpServletRequest)getRequest(); - final HttpServletResponse servletResponse = (HttpServletResponse)getResponse(); - Runnable run = new Runnable() { - public void run() { - DispatcherType type = (DispatcherType)request.getAttribute(Globals.DISPATCHER_TYPE_ATTR); - try { - //piggy back on the request dispatcher to ensure that filters etc get called. - //TODO SERVLET3 - async should this be include/forward or a new dispatch type - //javadoc suggests include with the type of DispatcherType.ASYNC - request.setAttribute(Globals.DISPATCHER_TYPE_ATTR, DispatcherType.ASYNC); - requestDispatcher.include(servletRequest, servletResponse); - }catch (Exception x) { - //log.error("Async.dispatch",x); - throw new RuntimeException(x); - }finally { - request.setAttribute(Globals.DISPATCHER_TYPE_ATTR, type); - } - } - }; - this.dispatch = run; - AtomicBoolean dispatched = new AtomicBoolean(false); - request.coyoteRequest.action(ActionCode.ACTION_ASYNC_DISPATCH, dispatched ); - if (!dispatched.get()) { - try { - doInternalDispatch(); - }catch (ServletException sx) { - throw new RuntimeException(sx); - }catch (IOException ix) { - throw new RuntimeException(ix); - } - } - - } else { - throw new IllegalStateException("Dispatch not allowed. Invalid state:"+state.get()); - } - } - - @Override - public ServletRequest getRequest() { - return getServletRequest(); - } - - @Override - public ServletResponse getResponse() { - return getServletResponse(); - } - - @Override - public void start(final Runnable run) { - if (state.compareAndSet(AsyncState.STARTED, AsyncState.DISPATCHING) || - state.compareAndSet(AsyncState.DISPATCHED, AsyncState.DISPATCHING)) { - // TODO SERVLET3 - async - final ServletContext sctx = getServletRequest().getServletContext(); - Runnable r = new Runnable() { - public void run() { - //TODO SERVLET3 - async - set context class loader when running the task. - try { - - run.run(); - }catch (Exception x) { - log.error("Unable to run async task.",x); - } - } - }; - this.dispatch = r; - AtomicBoolean dispatched = new AtomicBoolean(false); - request.coyoteRequest.action(ActionCode.ACTION_ASYNC_DISPATCH, dispatched ); - if (!dispatched.get()) { - try { - doInternalDispatch(); - }catch (ServletException sx) { - throw new RuntimeException(sx); - }catch (IOException ix) { - throw new RuntimeException(ix); - } - } - } else { - throw new IllegalStateException("Dispatch not allowed. Invalid state:"+state.get()); - } - } - - 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() { - servletRequest = null; - servletResponse = null; - listeners.clear(); - hasOriginalRequestAndResponse = true; - state.set(AsyncState.NOT_STARTED); - context = null; - timeout = -1; - } - - public boolean isStarted() { - return (state.get()!=AsyncState.NOT_STARTED); - } - - public void setStarted(Context context) { - if (state.compareAndSet(AsyncState.NOT_STARTED, AsyncState.STARTED)) { - this.context = context; - } else { - throw new IllegalStateException("Start illegal. Invalid state: "+state.get()); - } - } - - 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; - } - - public boolean isCompleted() { - return (state.get()==AsyncState.NOT_STARTED); - } - - public void setCompleted() { - this.state.set(AsyncState.NOT_STARTED); - } - - public void doInternalDispatch() throws ServletException, IOException { - if (this.state.compareAndSet(AsyncState.TIMING_OUT, AsyncState.DISPATCHED)) { - log.info("TIMING OUT!"); - boolean listenerInvoked = false; - for (AsyncListenerWrapper listener : listeners) { - listener.fireOnTimeout(); - listenerInvoked = true; - } - if (!listenerInvoked) { - ((HttpServletResponse)servletResponse).setStatus(500); - } - doInternalComplete(true); - } else if (this.state.compareAndSet(AsyncState.DISPATCHING, AsyncState.DISPATCHED)) { - if (this.dispatch!=null) { - try { - dispatch.run(); - } catch (RuntimeException x) { - doInternalComplete(true); - if (x.getCause() instanceof ServletException) throw (ServletException)x.getCause(); - if (x.getCause() instanceof IOException) throw (IOException)x.getCause(); - else throw new ServletException(x); - } finally { - dispatch = null; - } - } - } else if (this.state.get()==AsyncState.COMPLETING) { - doInternalComplete(false); - } else { - throw new IllegalStateException("Dispatch illegal. Invalid state: "+state.get()); - } - } - - public void doInternalComplete(boolean error) { - if (isCompleted()) return; - if (state.compareAndSet(AsyncState.STARTED, AsyncState.NOT_STARTED)) { - //this is the same as - //request.startAsync().complete(); - recycle(); - } else if (state.compareAndSet(AsyncState.COMPLETING, AsyncState.NOT_STARTED)) { - for (AsyncListenerWrapper wrapper : listeners) { - try { - wrapper.fireOnComplete(); - }catch (IOException x) { - //how does this propagate, or should it? - //TODO SERVLET3 - async - log.error("",x); - } - } - try { - if (!error) getResponse().flushBuffer(); - - }catch (Exception x) { - log.error("",x); - } - recycle(); - - } else { - throw new IllegalStateException("Complete illegal. Invalid state:"+state.get()); - } - } - - public AsyncState getState() { - return state.get(); - } - - protected void setState(AsyncState st) { - state.set(st); - } - - public long getAsyncTimeout() { - return timeout; - } - - public void setAsyncTimeout(long timeout) { - this.timeout = timeout; - request.coyoteRequest.action(ActionCode.ACTION_ASYNC_SETTIMEOUT,new Long(timeout)); - } - -} diff --git a/java/org/apache/catalina/connector/AsyncListenerWrapper.java b/java/org/apache/catalina/connector/AsyncListenerWrapper.java deleted file mode 100644 index ffdad5783..000000000 --- a/java/org/apache/catalina/connector/AsyncListenerWrapper.java +++ /dev/null @@ -1,72 +0,0 @@ -/* -* 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; - } - - - -} diff --git a/java/org/apache/catalina/connector/CoyoteAdapter.java b/java/org/apache/catalina/connector/CoyoteAdapter.java index 9571b80fa..2771dca3b 100644 --- a/java/org/apache/catalina/connector/CoyoteAdapter.java +++ b/java/org/apache/catalina/connector/CoyoteAdapter.java @@ -29,6 +29,7 @@ import org.apache.catalina.Context; import org.apache.catalina.Globals; import org.apache.catalina.Wrapper; import org.apache.tomcat.util.res.StringManager; +import org.apache.catalina.core.AsyncContextImpl; import org.apache.catalina.util.URLEncoder; import org.apache.coyote.ActionCode; import org.apache.coyote.Adapter; @@ -269,14 +270,8 @@ public class CoyoteAdapter AsyncContextImpl asyncConImpl = (AsyncContextImpl)request.getAsyncContext(); //TODO SERVLET3 - async //configure settings for timed out - asyncConImpl.setState(AsyncContextImpl.AsyncState.TIMING_OUT); + asyncConImpl.setTimeoutState(); } - if (status==SocketStatus.TIMEOUT) { - AsyncContextImpl asyncConImpl = (AsyncContextImpl)request.getAsyncContext(); - //TODO SERVLET3 - async - //configure settings for timed out - asyncConImpl.setState(AsyncContextImpl.AsyncState.TIMING_OUT); - } connector.getContainer().getPipeline().getFirst().invoke(request, response); }catch (RuntimeException x) { success = false; diff --git a/java/org/apache/catalina/connector/Request.java b/java/org/apache/catalina/connector/Request.java index 847d6f201..9a5c0c3b3 100644 --- a/java/org/apache/catalina/connector/Request.java +++ b/java/org/apache/catalina/connector/Request.java @@ -36,6 +36,7 @@ import java.util.TreeMap; import javax.security.auth.Subject; import javax.servlet.AsyncContext; +import javax.servlet.AsyncEvent; import javax.servlet.AsyncListener; import javax.servlet.DispatcherType; import javax.servlet.FilterChain; @@ -62,6 +63,7 @@ import org.apache.catalina.Manager; import org.apache.catalina.Realm; import org.apache.catalina.Session; import org.apache.catalina.Wrapper; +import org.apache.catalina.core.AsyncContextImpl; import org.apache.catalina.realm.GenericPrincipal; import org.apache.catalina.util.Enumerator; import org.apache.catalina.util.ParameterMap; @@ -1465,19 +1467,17 @@ public class Request public AsyncContext startAsync() { // TODO SERVLET3 - async + return startAsync(getRequest(),response.getResponse()); + } + + public AsyncContext startAsync(ServletRequest request, ServletResponse response) { if (!isAsyncSupported()) throw new IllegalStateException("Not supported."); if (asyncContext==null) asyncContext = new AsyncContextImpl(this); else if (asyncContext.isStarted()) throw new IllegalStateException("Already started."); asyncContext.setStarted(getContext()); - asyncContext.setServletRequest(getRequest()); - asyncContext.setServletResponse(response.getResponse()); - return asyncContext; - } - - public AsyncContext startAsync(ServletRequest request, ServletResponse response) { - startAsync(); asyncContext.setServletRequest(request); asyncContext.setServletResponse(response); + asyncContext.initEvent(); //TODO SERVLET3 - async - need to retrieve the ServletContext here //or just the webapp classloader associated with to do //run with start(Runnable) diff --git a/java/org/apache/catalina/core/AsyncContextImpl.java b/java/org/apache/catalina/core/AsyncContextImpl.java new file mode 100644 index 000000000..be4d6f126 --- /dev/null +++ b/java/org/apache/catalina/core/AsyncContextImpl.java @@ -0,0 +1,350 @@ +/* + * 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.core; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicReference; + +import javax.servlet.AsyncContext; +import javax.servlet.AsyncEvent; +import javax.servlet.AsyncListener; +import javax.servlet.DispatcherType; +import javax.servlet.RequestDispatcher; +import javax.servlet.ServletContext; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.apache.catalina.Context; +import org.apache.catalina.Globals; +import org.apache.catalina.connector.Request; +import org.apache.coyote.ActionCode; +import org.apache.juli.logging.Log; +import org.apache.juli.logging.LogFactory; +/** + * + * @author fhanik + * + */ +public class AsyncContextImpl implements AsyncContext { + + public static enum AsyncState { + NOT_STARTED, STARTED, DISPATCHING, DISPATCHED, COMPLETING, TIMING_OUT + } + + protected static Log log = LogFactory.getLog(AsyncContextImpl.class); + + private ServletRequest servletRequest = null; + private ServletResponse servletResponse = null; + private List listeners = new ArrayList(); + private boolean hasOriginalRequestAndResponse = true; + private volatile Runnable dispatch = null; + private Context context = null; + private AtomicReference state = new AtomicReference(AsyncState.NOT_STARTED); + private long timeout = -1; + private AsyncEvent event = null; + + private Request request; + + public AsyncContextImpl(Request request) { + //TODO SERVLET3 - async + this.request = request; + } + + @Override + public void complete() { + if (state.compareAndSet(AsyncState.STARTED, AsyncState.COMPLETING) || + state.compareAndSet(AsyncState.DISPATCHED, AsyncState.COMPLETING)) { + // TODO SERVLET3 - async + AtomicBoolean dispatched = new AtomicBoolean(false); + request.getCoyoteRequest().action(ActionCode.ACTION_ASYNC_COMPLETE,dispatched); + if (!dispatched.get()) doInternalComplete(false); + } else { + throw new IllegalStateException("Complete not allowed. Invalid state:"+state.get()); + } + + } + + @Override + public void dispatch() { + HttpServletRequest sr = (HttpServletRequest)getServletRequest(); + String path = sr.getRequestURI(); + String cpath = sr.getContextPath(); + if (cpath.length()>1) path = path.substring(cpath.length()); + dispatch(path); + } + + @Override + public void dispatch(String path) { + dispatch(request.getServletContext(),path); + } + + @Override + public void dispatch(ServletContext context, String path) { + // TODO SERVLET3 - async + if (state.compareAndSet(AsyncState.STARTED, AsyncState.DISPATCHING) || + state.compareAndSet(AsyncState.DISPATCHED, AsyncState.DISPATCHING)) { + + if (request.getAttribute(ASYNC_REQUEST_URI)==null) { + request.setAttribute(ASYNC_REQUEST_URI, request.getRequestURI()); + request.setAttribute(ASYNC_CONTEXT_PATH, request.getContextPath()); + request.setAttribute(ASYNC_SERVLET_PATH, request.getServletPath()); + request.setAttribute(ASYNC_QUERY_STRING, request.getQueryString()); + } + final RequestDispatcher requestDispatcher = context.getRequestDispatcher(path); + final HttpServletRequest servletRequest = (HttpServletRequest)getRequest(); + final HttpServletResponse servletResponse = (HttpServletResponse)getResponse(); + Runnable run = new Runnable() { + public void run() { + DispatcherType type = (DispatcherType)request.getAttribute(Globals.DISPATCHER_TYPE_ATTR); + try { + //piggy back on the request dispatcher to ensure that filters etc get called. + //TODO SERVLET3 - async should this be include/forward or a new dispatch type + //javadoc suggests include with the type of DispatcherType.ASYNC + request.setAttribute(Globals.DISPATCHER_TYPE_ATTR, DispatcherType.ASYNC); + requestDispatcher.include(servletRequest, servletResponse); + }catch (Exception x) { + //log.error("Async.dispatch",x); + throw new RuntimeException(x); + }finally { + request.setAttribute(Globals.DISPATCHER_TYPE_ATTR, type); + } + } + }; + this.dispatch = run; + AtomicBoolean dispatched = new AtomicBoolean(false); + request.getCoyoteRequest().action(ActionCode.ACTION_ASYNC_DISPATCH, dispatched ); + if (!dispatched.get()) { + try { + doInternalDispatch(); + }catch (ServletException sx) { + throw new RuntimeException(sx); + }catch (IOException ix) { + throw new RuntimeException(ix); + } + } + + } else { + throw new IllegalStateException("Dispatch not allowed. Invalid state:"+state.get()); + } + } + + @Override + public ServletRequest getRequest() { + return getServletRequest(); + } + + @Override + public ServletResponse getResponse() { + return getServletResponse(); + } + + @Override + public void start(final Runnable run) { + if (state.compareAndSet(AsyncState.STARTED, AsyncState.DISPATCHING) || + state.compareAndSet(AsyncState.DISPATCHED, AsyncState.DISPATCHING)) { + // TODO SERVLET3 - async + final ServletContext sctx = getServletRequest().getServletContext(); + Runnable r = new Runnable() { + public void run() { + //TODO SERVLET3 - async - set context class loader when running the task. + try { + + run.run(); + }catch (Exception x) { + log.error("Unable to run async task.",x); + } + } + }; + this.dispatch = r; + AtomicBoolean dispatched = new AtomicBoolean(false); + request.getCoyoteRequest().action(ActionCode.ACTION_ASYNC_DISPATCH, dispatched ); + if (!dispatched.get()) { + try { + doInternalDispatch(); + }catch (ServletException sx) { + throw new RuntimeException(sx); + }catch (IOException ix) { + throw new RuntimeException(ix); + } + } + } else { + throw new IllegalStateException("Dispatch not allowed. Invalid state:"+state.get()); + } + } + + public void addAsyncListener(AsyncListener listener) { + AsyncListenerWrapper wrapper = new AsyncListenerWrapper(); + wrapper.setListener(listener); + listeners.add(wrapper); + } + + public void addAsyncListener(AsyncListener listener, ServletRequest servletRequest, ServletResponse servletResponse) { + AsyncListenerWrapper wrapper = new AsyncListenerWrapper(); + wrapper.setListener(listener); + listeners.add(wrapper); + } + + + public void recycle() { + servletRequest = null; + servletResponse = null; + listeners.clear(); + hasOriginalRequestAndResponse = true; + state.set(AsyncState.NOT_STARTED); + context = null; + timeout = -1; + event = null; + } + + public boolean isStarted() { + return (state.get()!=AsyncState.NOT_STARTED); + } + + public void setStarted(Context context) { + if (state.compareAndSet(AsyncState.NOT_STARTED, AsyncState.STARTED)) { + this.context = context; + } else { + throw new IllegalStateException("Start illegal. Invalid state: "+state.get()); + } + } + + 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; + } + + public boolean isCompleted() { + return (state.get()==AsyncState.NOT_STARTED); + } + + public void setCompleted() { + this.state.set(AsyncState.NOT_STARTED); + } + + public void doInternalDispatch() throws ServletException, IOException { + if (this.state.compareAndSet(AsyncState.TIMING_OUT, AsyncState.DISPATCHED)) { + log.debug("TIMING OUT!"); + boolean listenerInvoked = false; + for (AsyncListenerWrapper listener : listeners) { + listener.fireOnTimeout(event); + listenerInvoked = true; + } + if (!listenerInvoked) { + ((HttpServletResponse)servletResponse).setStatus(500); + } + doInternalComplete(true); + } else if (this.state.compareAndSet(AsyncState.DISPATCHING, AsyncState.DISPATCHED)) { + if (this.dispatch!=null) { + try { + dispatch.run(); + } catch (RuntimeException x) { + doInternalComplete(true); + if (x.getCause() instanceof ServletException) throw (ServletException)x.getCause(); + if (x.getCause() instanceof IOException) throw (IOException)x.getCause(); + else throw new ServletException(x); + } finally { + dispatch = null; + } + } + } else if (this.state.get()==AsyncState.COMPLETING) { + doInternalComplete(false); + } else { + throw new IllegalStateException("Dispatch illegal. Invalid state: "+state.get()); + } + } + + public void doInternalComplete(boolean error) { + if (isCompleted()) return; + if (state.compareAndSet(AsyncState.STARTED, AsyncState.NOT_STARTED)) { + //this is the same as + //request.startAsync().complete(); + recycle(); + } else if (state.compareAndSet(AsyncState.COMPLETING, AsyncState.NOT_STARTED)) { + for (AsyncListenerWrapper wrapper : listeners) { + try { + wrapper.fireOnComplete(event); + }catch (IOException x) { + //how does this propagate, or should it? + //TODO SERVLET3 - async + log.error("",x); + } + } + try { + if (!error) getResponse().flushBuffer(); + + }catch (Exception x) { + log.error("",x); + } + recycle(); + + } else { + throw new IllegalStateException("Complete illegal. Invalid state:"+state.get()); + } + } + + public AsyncState getState() { + return state.get(); + } + + protected void setState(AsyncState st) { + state.set(st); + } + + public long getAsyncTimeout() { + return timeout; + } + + public void setAsyncTimeout(long timeout) { + this.timeout = timeout; + request.getCoyoteRequest().action(ActionCode.ACTION_ASYNC_SETTIMEOUT,new Long(timeout)); + } + + public void setTimeoutState() { + state.set(AsyncState.TIMING_OUT); + } + + public void initEvent() { + event = new AsyncEvent(getRequest(),getResponse()); + } + +} diff --git a/java/org/apache/catalina/core/AsyncListenerWrapper.java b/java/org/apache/catalina/core/AsyncListenerWrapper.java new file mode 100644 index 000000000..0f4085a9b --- /dev/null +++ b/java/org/apache/catalina/core/AsyncListenerWrapper.java @@ -0,0 +1,55 @@ +/* +* 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.core; + +import java.io.IOException; + +import javax.servlet.AsyncEvent; +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; + + public void fireOnComplete(AsyncEvent event) throws IOException { + // TODO SERVLET 3 - async + listener.onComplete(event); + } + + + public void fireOnTimeout(AsyncEvent event) throws IOException { + // TODO SERVLET 3 - async + listener.onTimeout(event); + } + + public AsyncListener getListener() { + return listener; + } + + public void setListener(AsyncListener listener) { + this.listener = listener; + } + + + +} diff --git a/java/org/apache/catalina/core/StandardWrapperValve.java b/java/org/apache/catalina/core/StandardWrapperValve.java index 2f0b266ba..74522f062 100644 --- a/java/org/apache/catalina/core/StandardWrapperValve.java +++ b/java/org/apache/catalina/core/StandardWrapperValve.java @@ -33,7 +33,6 @@ import org.apache.catalina.CometEvent; import org.apache.catalina.CometProcessor; import org.apache.catalina.Context; import org.apache.catalina.Globals; -import org.apache.catalina.connector.AsyncContextImpl; import org.apache.catalina.connector.ClientAbortException; import org.apache.catalina.connector.Request; import org.apache.catalina.connector.Response; diff --git a/webapps/examples/WEB-INF/classes/async/Async0.java b/webapps/examples/WEB-INF/classes/async/Async0.java index 777f077be..6929141f4 100644 --- a/webapps/examples/WEB-INF/classes/async/Async0.java +++ b/webapps/examples/WEB-INF/classes/async/Async0.java @@ -48,7 +48,7 @@ public class Async0 extends HttpServlet { try { Thread.currentThread().setName("Async0-Thread"); log.info("Putting AsyncThread to sleep"); - Thread.sleep(10*1000); + Thread.sleep(2*1000); log.info("Dispatching"); actx.dispatch(); }catch (InterruptedException x) { diff --git a/webapps/examples/WEB-INF/classes/async/Async1.java b/webapps/examples/WEB-INF/classes/async/Async1.java index 98708e5b0..497bfb26b 100644 --- a/webapps/examples/WEB-INF/classes/async/Async1.java +++ b/webapps/examples/WEB-INF/classes/async/Async1.java @@ -42,7 +42,7 @@ public class Async1 extends HttpServlet { String path = "/jsp/async/async1.jsp"; Thread.currentThread().setName("Async1-Thread"); log.info("Putting AsyncThread to sleep"); - Thread.sleep(10*1000); + Thread.sleep(2*1000); log.info("Dispatching to "+path); actx.dispatch(path); }catch (InterruptedException x) { diff --git a/webapps/examples/WEB-INF/classes/async/Async2.java b/webapps/examples/WEB-INF/classes/async/Async2.java index 5cda1ec28..0ef07ad9c 100644 --- a/webapps/examples/WEB-INF/classes/async/Async2.java +++ b/webapps/examples/WEB-INF/classes/async/Async2.java @@ -41,7 +41,7 @@ public class Async2 extends HttpServlet { try { Thread.currentThread().setName("Async2-Thread"); log.info("Putting AsyncThread to sleep"); - Thread.sleep(10*1000); + Thread.sleep(2*1000); log.info("Writing data."); actx.getResponse().getWriter().write("Output from background thread. Time:"+System.currentTimeMillis()+"\n"); actx.complete();