/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright (c) 2017-2017 Oracle and/or its affiliates. All rights reserved.
*
* The contents of this file are subject to the terms of either the GNU
* General Public License Version 2 only ("GPL") or the Common Development
* and Distribution License("CDDL") (collectively, the "License"). You
* may not use this file except in compliance with the License. You can
* obtain a copy of the License at
* https://oss.oracle.com/licenses/CDDL+GPL-1.1
* or LICENSE.txt. See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each
* file and include the License file at LICENSE.txt.
*
* GPL Classpath Exception:
* Oracle designates this particular file as subject to the "Classpath"
* exception as provided by Oracle in the GPL Version 2 section of the License
* file that accompanied this code.
*
* Modifications:
* If applicable, add the following below the License Header, with the fields
* enclosed by brackets [] replaced by your own identifying information:
* "Portions Copyright [year] [name of copyright owner]"
*
* Contributor(s):
* If you wish your version of this file to be governed by only the CDDL or
* only the GPL Version 2, indicate your decision by adding "[Contributor]
* elects to include this software in this distribution under the [CDDL or GPL
* Version 2] license." If you don't indicate a single choice of license, a
* recipient has the option to distribute your version of this file under
* either the CDDL, the GPL Version 2 or to extend the choice of license to
* its licensees as provided above. However, if you add GPL Version 2 code
* and therefore, elected the GPL Version 2 license, then the option applies
* only if the new code is made subject to such option by the copyright
* holder.
*/
package javax.servlet;
/**
* Class representing the execution context for an asynchronous operation
* that was initiated on a ServletRequest.
*
* <p>An AsyncContext is created and initialized by a call to
* {@link ServletRequest#startAsync()} or
* {@link ServletRequest#startAsync(ServletRequest, ServletResponse)}.
* Repeated invocations of these methods will return the same AsyncContext
* instance, reinitialized as appropriate.
*
* <p>In the event that an asynchronous operation has timed out, the
* container must run through these steps:
* <ol>
* <li>Invoke, at their {@link AsyncListener#onTimeout onTimeout} method, all
* {@link AsyncListener} instances registered with the ServletRequest
* on which the asynchronous operation was initiated.</li>
* <li>If none of the listeners called {@link #complete} or any of the
* {@link #dispatch} methods, perform an error dispatch with a status code
* equal to <tt>HttpServletResponse.SC_INTERNAL_SERVER_ERROR</tt>.</li>
* <li>If no matching error page was found, or the error page did not call
* {@link #complete} or any of the {@link #dispatch} methods, call
* {@link #complete}.</li>
* </ol>
*
* @since Servlet 3.0
*/
public interface
AsyncContext {
/**
* The name of the request attribute under which the original
* request URI is made available to the target of a
* {@link #dispatch(String)} or {@link #dispatch(ServletContext,String)}
*/
static final
String ASYNC_REQUEST_URI = "javax.servlet.async.request_uri";
/**
* The name of the request attribute under which the original
* context path is made available to the target of a
* {@link #dispatch(String)} or {@link #dispatch(ServletContext,String)}
*/
static final
String ASYNC_CONTEXT_PATH = "javax.servlet.async.context_path";
/**
* The name of the request attribute under which the original
* {@link javax.servlet.http.HttpServletMapping} is made available to the target of a
* {@link #dispatch(String)} or {@link #dispatch(ServletContext,String)}
*/
static final
String ASYNC_MAPPING = "javax.servlet.async.mapping";
/**
* The name of the request attribute under which the original
* path info is made available to the target of a
* {@link #dispatch(String)} or {@link #dispatch(ServletContext,String)}
*/
static final
String ASYNC_PATH_INFO = "javax.servlet.async.path_info";
/**
* The name of the request attribute under which the original
* servlet path is made available to the target of a
* {@link #dispatch(String)} or {@link #dispatch(ServletContext,String)}
*/
static final
String ASYNC_SERVLET_PATH = "javax.servlet.async.servlet_path";
/**
* The name of the request attribute under which the original
* query string is made available to the target of a
* {@link #dispatch(String)} or {@link #dispatch(ServletContext,String)}
*/
static final
String ASYNC_QUERY_STRING = "javax.servlet.async.query_string";
/**
* Gets the request that was used to initialize this AsyncContext
* by calling {@link ServletRequest#startAsync()} or
* {@link ServletRequest#startAsync(ServletRequest, ServletResponse)}.
*
* @return the request that was used to initialize this AsyncContext
*
* @exception IllegalStateException if {@link #complete} or any of the
* {@link #dispatch} methods has been
* called in the asynchronous cycle
*/
public
ServletRequest getRequest();
/**
* Gets the response that was used to initialize this AsyncContext
* by calling {@link ServletRequest#startAsync()} or
* {@link ServletRequest#startAsync(ServletRequest, ServletResponse)}.
*
* @return the response that was used to initialize this AsyncContext
*
* @exception IllegalStateException if {@link #complete} or any of the
* {@link #dispatch} methods has been
* called in the asynchronous cycle
*/
public
ServletResponse getResponse();
/**
* Checks if this AsyncContext was initialized with the original or
* application-wrapped request and response objects.
*
* <p>This information may be used by filters invoked in the
* <i>outbound</i> direction, after a request was put into
* asynchronous mode, to determine whether any request and/or response
* wrappers that they added during their <i>inbound</i> invocation need
* to be preserved for the duration of the asynchronous operation, or may
* be released.
*
* @return true if this AsyncContext was initialized with the original
* request and response objects by calling
* {@link ServletRequest#startAsync()}, or if it was initialized by
* calling
* {@link ServletRequest#startAsync(ServletRequest, ServletResponse)},
* and neither the ServletRequest nor ServletResponse arguments
* carried any application-provided wrappers; false otherwise
*/
public boolean
hasOriginalRequestAndResponse();
/**
* Dispatches the request and response objects of this AsyncContext
* to the servlet container.
*
* <p>If the asynchronous cycle was started with
* {@link ServletRequest#startAsync(ServletRequest, ServletResponse)},
* and the request passed is an instance of HttpServletRequest,
* then the dispatch is to the URI returned by
* {@link javax.servlet.http.HttpServletRequest#getRequestURI}.
* Otherwise, the dispatch is to the URI of the request when it was
* last dispatched by the container.
*
* <p>The following sequence illustrates how this will work:
* <pre>{@code
* // REQUEST dispatch to /url/A
* AsyncContext ac = request.startAsync();
* ...
* ac.dispatch(); // ASYNC dispatch to /url/A
*
* // REQUEST to /url/A
* // FORWARD dispatch to /url/B
* request.getRequestDispatcher("/url/B").forward(request,response);
* // Start async operation from within the target of the FORWARD
* // dispatch
* ac = request.startAsync();
* ...
* ac.dispatch(); // ASYNC dispatch to /url/A
*
* // REQUEST to /url/A
* // FORWARD dispatch to /url/B
* request.getRequestDispatcher("/url/B").forward(request,response);
* // Start async operation from within the target of the FORWARD
* // dispatch
* ac = request.startAsync(request,response);
* ...
* ac.dispatch(); // ASYNC dispatch to /url/B
* }</pre>
*
* <p>This method returns immediately after passing the request
* and response objects to a container managed thread, on which the
* dispatch operation will be performed.
* If this method is called before the container-initiated dispatch
* that called <tt>startAsync</tt> has returned to the container, the
* dispatch operation will be delayed until after the container-initiated
* dispatch has returned to the container.
*
* <p>The dispatcher type of the request is set to
* <tt>DispatcherType.ASYNC</tt>. Unlike
* {@link RequestDispatcher#forward(ServletRequest, ServletResponse)
* forward dispatches}, the response buffer and
* headers will not be reset, and it is legal to dispatch even if the
* response has already been committed.
*
* <p>Control over the request and response is delegated
* to the dispatch target, and the response will be closed when the
* dispatch target has completed execution, unless
* {@link ServletRequest#startAsync()} or
* {@link ServletRequest#startAsync(ServletRequest, ServletResponse)}
* are called.
*
* <p>Any errors or exceptions that may occur during the execution
* of this method must be caught and handled by the container, as
* follows:
* <ol>
* <li>Invoke, at their {@link AsyncListener#onError onError} method, all
* {@link AsyncListener} instances registered with the ServletRequest
* for which this AsyncContext was created, and make the caught
* <tt>Throwable</tt> available via {@link AsyncEvent#getThrowable}.</li>
* <li>If none of the listeners called {@link #complete} or any of the
* {@link #dispatch} methods, perform an error dispatch with a status code
* equal to <tt>HttpServletResponse.SC_INTERNAL_SERVER_ERROR</tt>, and
* make the above <tt>Throwable</tt> available as the value of the
* <tt>RequestDispatcher.ERROR_EXCEPTION</tt> request attribute.</li>
* <li>If no matching error page was found, or the error page did not call
* {@link #complete} or any of the {@link #dispatch} methods, call
* {@link #complete}.</li>
* </ol>
*
* <p>There can be at most one asynchronous dispatch operation per
* asynchronous cycle, which is started by a call to one of the
* {@link ServletRequest#startAsync} methods. Any attempt to perform an
* additional asynchronous dispatch operation within the same
* asynchronous cycle will result in an IllegalStateException.
* If startAsync is subsequently called on the dispatched request,
* then any of the dispatch or {@link #complete} methods may be called.
*
* @throws IllegalStateException if one of the dispatch methods
* has been called and the startAsync method has not been
* called during the resulting dispatch, or if {@link #complete}
* was called
*
* @see ServletRequest#getDispatcherType
*/
public void
dispatch();
/**
* Dispatches the request and response objects of this AsyncContext
* to the given <tt>path</tt>.
*
* <p>The <tt>path</tt> parameter is interpreted in the same way
* as in {@link ServletRequest#getRequestDispatcher(String)}, within
* the scope of the {@link ServletContext} from which this
* AsyncContext was initialized.
*
* <p>All path related query methods of the request must reflect the
* dispatch target, while the original request URI, context path,
* path info, servlet path, and query string may be recovered from
* the {@link #ASYNC_REQUEST_URI}, {@link #ASYNC_CONTEXT_PATH},
* {@link #ASYNC_PATH_INFO}, {@link #ASYNC_SERVLET_PATH}, and
* {@link #ASYNC_QUERY_STRING} attributes of the request. These
* attributes will always reflect the original path elements, even under
* repeated dispatches.
*
* <p>There can be at most one asynchronous dispatch operation per
* asynchronous cycle, which is started by a call to one of the
* {@link ServletRequest#startAsync} methods. Any attempt to perform an
* additional asynchronous dispatch operation within the same
* asynchronous cycle will result in an IllegalStateException.
* If startAsync is subsequently called on the dispatched request,
* then any of the dispatch or {@link #complete} methods may be called.
*
* <p>See {@link #dispatch()} for additional details, including error
* handling.
*
* @param path the path of the dispatch target, scoped to the
* ServletContext from which this AsyncContext was initialized
*
* @throws IllegalStateException if one of the dispatch methods
* has been called and the startAsync method has not been
* called during the resulting dispatch, or if {@link #complete}
* was called
*
* @see ServletRequest#getDispatcherType
*/
public void
dispatch(
String path);
/**
* Dispatches the request and response objects of this AsyncContext
* to the given <tt>path</tt> scoped to the given <tt>context</tt>.
*
* <p>The <tt>path</tt> parameter is interpreted in the same way
* as in {@link ServletRequest#getRequestDispatcher(String)}, except that
* it is scoped to the given <tt>context</tt>.
*
* <p>All path related query methods of the request must reflect the
* dispatch target, while the original request URI, context path,
* path info, servlet path, and query string may be recovered from
* the {@link #ASYNC_REQUEST_URI}, {@link #ASYNC_CONTEXT_PATH},
* {@link #ASYNC_PATH_INFO}, {@link #ASYNC_SERVLET_PATH}, and
* {@link #ASYNC_QUERY_STRING} attributes of the request. These
* attributes will always reflect the original path elements, even under
* repeated dispatches.
*
* <p>There can be at most one asynchronous dispatch operation per
* asynchronous cycle, which is started by a call to one of the
* {@link ServletRequest#startAsync} methods. Any attempt to perform an
* additional asynchronous dispatch operation within the same
* asynchronous cycle will result in an IllegalStateException.
* If startAsync is subsequently called on the dispatched request,
* then any of the dispatch or {@link #complete} methods may be called.
*
* <p>See {@link #dispatch()} for additional details, including error
* handling.
*
* @param context the ServletContext of the dispatch target
* @param path the path of the dispatch target, scoped to the given
* ServletContext
*
* @throws IllegalStateException if one of the dispatch methods
* has been called and the startAsync method has not been
* called during the resulting dispatch, or if {@link #complete}
* was called
*
* @see ServletRequest#getDispatcherType
*/
public void
dispatch(
ServletContext context,
String path);
/**
* Completes the asynchronous operation that was started on the request
* that was used to initialze this AsyncContext, closing the response
* that was used to initialize this AsyncContext.
*
* <p>Any listeners of type {@link AsyncListener} that were registered
* with the ServletRequest for which this AsyncContext was created will
* be invoked at their {@link AsyncListener#onComplete(AsyncEvent)
* onComplete} method.
*
* <p>It is legal to call this method any time after a call to
* {@link ServletRequest#startAsync()} or
* {@link ServletRequest#startAsync(ServletRequest, ServletResponse)},
* and before a call to one of the <tt>dispatch</tt> methods
* of this class.
* If this method is called before the container-initiated dispatch
* that called <tt>startAsync</tt> has returned to the container, then
* the call will not take effect (and any invocations of
* {@link AsyncListener#onComplete(AsyncEvent)} will be delayed) until
* after the container-initiated dispatch has returned to the container.
*/
public void
complete();
/**
* Causes the container to dispatch a thread, possibly from a managed
* thread pool, to run the specified <tt>Runnable</tt>. The container may
* propagate appropriate contextual information to the <tt>Runnable</tt>.
*
* @param run the asynchronous handler
*/
public void
start(
Runnable run);
/**
* Registers the given {@link AsyncListener} with the most recent
* asynchronous cycle that was started by a call to one of the
* {@link ServletRequest#startAsync} methods.
*
* <p>The given AsyncListener will receive an {@link AsyncEvent} when
* the asynchronous cycle completes successfully, times out, results
* in an error, or a new asynchronous cycle is being initiated via
* one of the {@link ServletRequest#startAsync} methods.
*
* <p>AsyncListener instances will be notified in the order in which
* they were added.
*
* <p>If {@link ServletRequest#startAsync(ServletRequest, ServletResponse)}
* or {@link ServletRequest#startAsync} is called,
* the exact same request and response objects are available from the
* {@link AsyncEvent} when the {@link AsyncListener} is notified.
*
* @param listener the AsyncListener to be registered
*
* @throws IllegalStateException if this method is called after
* the container-initiated dispatch, during which one of the
* {@link ServletRequest#startAsync} methods was called, has
* returned to the container
*/
public void
addListener(
AsyncListener listener);
/**
* Registers the given {@link AsyncListener} with the most recent
* asynchronous cycle that was started by a call to one of the
* {@link ServletRequest#startAsync} methods.
*
* <p>The given AsyncListener will receive an {@link AsyncEvent} when
* the asynchronous cycle completes successfully, times out, results
* in an error, or a new asynchronous cycle is being initiated via
* one of the {@link ServletRequest#startAsync} methods.
*
* <p>AsyncListener instances will be notified in the order in which
* they were added.
*
* <p>The given ServletRequest and ServletResponse objects will
* be made available to the given AsyncListener via the
* {@link AsyncEvent#getSuppliedRequest getSuppliedRequest} and
* {@link AsyncEvent#getSuppliedResponse getSuppliedResponse} methods,
* respectively, of the {@link AsyncEvent} delivered to it. These objects
* should not be read from or written to, respectively, at the time the
* AsyncEvent is delivered, because additional wrapping may have
* occurred since the given AsyncListener was registered, but may be used
* in order to release any resources associated with them.
*
* @param listener the AsyncListener to be registered
* @param servletRequest the ServletRequest that will be included
* in the AsyncEvent
* @param servletResponse the ServletResponse that will be included
* in the AsyncEvent
*
* @throws IllegalStateException if this method is called after
* the container-initiated dispatch, during which one of the
* {@link ServletRequest#startAsync} methods was called, has
* returned to the container
*/
public void
addListener(
AsyncListener listener,
ServletRequest servletRequest,
ServletResponse servletResponse);
/**
* Instantiates the given {@link AsyncListener} class.
*
* <p>The returned AsyncListener instance may be further customized
* before it is registered with this AsyncContext via a call to one of
* the <code>addListener</code> methods.
*
* <p>The given AsyncListener class must define a zero argument
* constructor, which is used to instantiate it.
*
* <p>This method supports resource injection if the given
* <tt>clazz</tt> represents a Managed Bean.
* See the Java EE platform and JSR 299 specifications for additional
* details about Managed Beans and resource injection.
* <p>This method supports any annotations applicable to AsyncListener.
*
* @param <T> the class of the object to instantiate
* @param clazz the AsyncListener class to instantiate
*
* @return the new AsyncListener instance
*
* @throws ServletException if the given <tt>clazz</tt> fails to be
* instantiated
*/
public <T extends
AsyncListener> T
createListener(
Class<T>
clazz)
throws
ServletException;
/**
* Sets the timeout (in milliseconds) for this AsyncContext.
*
* <p>The timeout applies to this AsyncContext once the
* container-initiated dispatch during which one of the
* {@link ServletRequest#startAsync} methods was called has
* returned to the container.
*
* <p>The timeout will expire if neither the {@link #complete} method
* nor any of the dispatch methods are called. A timeout value of
* zero or less indicates no timeout.
*
* <p>If {@link #setTimeout} is not called, then the container's
* default timeout, which is available via a call to
* {@link #getTimeout}, will apply.
*
* <p>The default value is <code>30000</code> ms.
*
* @param timeout the timeout in milliseconds
*
* @throws IllegalStateException if this method is called after
* the container-initiated dispatch, during which one of the
* {@link ServletRequest#startAsync} methods was called, has
* returned to the container
*/
public void
setTimeout(long
timeout);
/**
* Gets the timeout (in milliseconds) for this AsyncContext.
*
* <p>This method returns the container's default timeout for
* asynchronous operations, or the timeout value passed to the most
* recent invocation of {@link #setTimeout}.
*
* <p>A timeout value of zero or less indicates no timeout.
*
* @return the timeout in milliseconds
*/
public long
getTimeout();
}