public interface Continuation
The continuation mechanism is a portable mechanism that will work
asynchronously without additional configuration of all jetty-7,
jetty-8 and Servlet 3.0 containers. With the addition of
the ContinuationFilter
, the mechanism will also work
asynchronously on jetty-6 and non-asynchronously on any
servlet 2.5 container.
The Continuation API is a simplification of the richer async API provided by the servlet-3.0 and an enhancement of the continuation API that was introduced with jetty-6.
A continuation object is obtained for a request by calling the
factory method ContinuationSupport.getContinuation(ServletRequest)
.
The continuation type returned will depend on the servlet container
being used.
There are two distinct style of operation of the continuation API.
The suspend/resume style is used when a servlet and/or filter is used to generate the response after a asynchronous wait that is terminated by an asynchronous handler.
Filter/Servlet: // if we need to get asynchronous results Object results = request.getAttribute("results); if (results==null) { Continuation continuation = ContinuationSupport.getContinuation(request); continuation.suspend(); myAsyncHandler.register(continuation); return; // or continuation.undispatch(); } async wait ... Async Handler: // when the waited for event happens continuation.setAttribute("results",event); continuation.resume(); Filter/Servlet: // when the request is redispatched if (results==null) { ... // see above } else { response.getOutputStream().write(process(results)); }
The suspend/complete style is used when an asynchronous handler is used to generate the response:
Filter/Servlet: // when we want to enter asynchronous mode Continuation continuation = ContinuationSupport.getContinuation(request); continuation.suspend(response); // response may be wrapped myAsyncHandler.register(continuation); return; // or continuation.undispatch(); Wrapping Filter: // any filter that had wrapped the response should be implemented like: try { chain.doFilter(request,wrappedResponse); } finally { if (!continuation.isResponseWrapped()) wrappedResponse.finish() else continuation.addContinuationListener(myCompleteListener) } async wait ... Async Handler: // when the async event happens continuation.getServletResponse().getOutputStream().write(process(event)); continuation.complete()
If a continuation is suspended, but neither complete()
or resume()
is
called during the period set by setTimeout(long)
, then the continuation will
expire and isExpired()
will return true.
When a continuation expires, the ContinuationListener.onTimeout(Continuation)
method is called on any ContinuationListener
that has been registered via the
addContinuationListener(ContinuationListener)
method. The onTimeout handlers
may write a response and call complete()
. If complete()
is not called,
then the container will redispatch the request as if resume()
had been called,
except that isExpired()
will be true and isResumed()
will be false.
ContinuationSupport
,
ContinuationListener
Modifier and Type | Method and Description |
---|---|
void |
addContinuationListener(ContinuationListener listener)
Add a ContinuationListener.
|
void |
complete()
Complete a suspended request.
|
Object |
getAttribute(String name)
Get a request attribute.
|
ServletResponse |
getServletResponse()
Get the suspended response.
|
boolean |
isExpired() |
boolean |
isInitial() |
boolean |
isResponseWrapped()
Is the suspended response wrapped.
|
boolean |
isResumed() |
boolean |
isSuspended() |
void |
removeAttribute(String name)
Remove a request attribute.
|
void |
resume()
Resume a suspended request.
|
void |
setAttribute(String name,
Object attribute)
Set a request attribute.
|
void |
setTimeout(long timeoutMs)
Set the continuation timeout.
|
void |
suspend()
Suspend the processing of the request and associated
ServletResponse . |
void |
suspend(ServletResponse response)
Suspend the processing of the request and associated
ServletResponse . |
void |
undispatch()
Undispatch the request.
|
static final String ATTRIBUTE
void setTimeout(long timeoutMs)
timeoutMs
- The time in milliseconds to wait before expiring this
continuation after a call to suspend()
or suspend(ServletResponse)
.
A timeout of <=0 means the continuation will never expire.void suspend()
ServletResponse
.
After this method has been called, the lifecycle of the request will be
extended beyond the return to the container from the
Servlet#service(ServletRequest, ServletResponse)
method and
Filter#doFilter(ServletRequest, ServletResponse, FilterChain)
calls. When a suspended request is returned to the container after
a dispatch, then the container will not commit the associated response
(unless an exception other than ContinuationThrowable
is thrown).
When the thread calling the filter chain and/or servlet has returned to the container with a suspended request, the thread is freed for other tasks and the request is held until either:
resume()
.complete()
.
Typically suspend with no arguments is uses when a call to resume()
is expected. If a call to complete()
is expected, then the
suspend(ServletResponse)
method should be used instead of this method.
IllegalStateException
- If the request cannot be suspendedvoid suspend(ServletResponse response)
ServletResponse
.
After this method has been called, the lifecycle of the request will be
extended beyond the return to the container from the
Servlet#service(ServletRequest, ServletResponse)
method and
Filter#doFilter(ServletRequest, ServletResponse, FilterChain)
calls. When a suspended request is returned to the container after
a dispatch, then the container will not commit the associated response
(unless an exception other than ContinuationThrowable
is thrown).
When the thread calling the filter chain and/or servlet has returned to the container with a suspended request, the thread is freed for other tasks and the request is held until either:
resume()
.complete()
.
Typically suspend with a response argument is uses when a call to complete()
is expected. If a call to resume()
is expected, then the
suspend()
method should be used instead of this method.
Filters that may wrap the response object should check isResponseWrapped()
to decide if they should destroy/finish the wrapper. If isResponseWrapped()
returns true, then the wrapped request has been passed to the asynchronous
handler and the wrapper should not be destroyed/finished until after a call to
complete()
(potentially using a ContinuationListener.onComplete(Continuation)
listener).
response
- The response to return via a call to getServletResponse()
IllegalStateException
- If the request cannot be suspendedvoid resume()
This method can be called by any thread that has been passed a reference
to a continuation. When called the request is redispatched to the
normal filter chain and servlet processing with isInitial()
false.
If resume is called before a suspended request is returned to the
container (ie the thread that called suspend()
is still
within the filter chain and/or servlet service method), then the resume
does not take effect until the call to the filter chain and/or servlet
returns to the container. In this case both isSuspended()
and
isResumed()
return true. Multiple calls to resume are ignored.
Typically resume() is used after a call to suspend()
with
no arguments. The dispatch after a resume call will use the original
request and response objects, even if suspend(ServletResponse)
had been passed a wrapped response.
IllegalStateException
- if the request is not suspended.suspend()
void complete()
This method can be called by any thread that has been passed a reference to a suspended request. When a request is completed, the associated response object committed and flushed. The request is not redispatched.
If complete is called before a suspended request is returned to the
container (ie the thread that called suspend()
is still
within the filter chain and/or servlet service method), then the complete
does not take effect until the call to the filter chain and/or servlet
returns to the container. In this case both isSuspended()
and
isResumed()
return true.
Typically resume() is used after a call to suspend(ServletResponse)
with
a possibly wrapped response. The async handler should use the response
provided by getServletResponse()
to write the response before
calling complete()
. If the request was suspended with a
call to suspend()
then no response object will be available via
getServletResponse()
.
Once complete has been called and any thread calling the filter chain and/or servlet chain has returned to the container, the request lifecycle is complete. The container is able to recycle request objects, so it is not valid hold a request or continuation reference after the end of the life cycle.
IllegalStateException
- if the request is not suspended.suspend()
boolean isSuspended()
suspend()
has been called and before the
request has been redispatched due to being resumed, completed or
timed out.boolean isResumed()
resume()
. Returns false after any subsequent call to
suspendboolean isExpired()
boolean isInitial()
boolean isResponseWrapped()
Filters that wrap the response object should check this method to
determine if they should destroy/finish the wrapped response. If
the request was suspended with a call to suspend(ServletResponse)
that passed the wrapped response, then the filter should register
a ContinuationListener
to destroy/finish the wrapped response
during a call to ContinuationListener.onComplete(Continuation)
.
suspend(ServletResponse)
has been passed a
ServletResponseWrapper
instance.ServletResponse getServletResponse()
ServletResponse
passed to suspend(ServletResponse)
.void addContinuationListener(ContinuationListener listener)
listener
- void setAttribute(String name, Object attribute)
ServletRequest#setAttribute(String, Object)
method on the associated request object.
This is a thread safe call and may be called by any thread.name
- the attribute nameattribute
- the attribute valueObject getAttribute(String name)
ServletRequest#getAttribute(String)
method on the associated request object.
This is a thread safe call and may be called by any thread.name
- the attribute namevoid removeAttribute(String name)
ServletRequest#removeAttribute(String)
method on the associated request object.
This is a thread safe call and may be called by any thread.name
- the attribute namevoid undispatch() throws ContinuationThrowable
This method can be called on a suspended continuation in order
to exit the dispatch to the filter/servlet by throwing a ContinuationThrowable
which is caught either by the container or the ContinuationFilter
.
This is an alternative to simply returning from the dispatch in the case
where filters in the filter chain may not be prepared to handle a suspended
request.
ContinuationThrowable
- thrown if the request is suspended. The instance of the
exception may be reused on subsequent calls, so the stack frame may not be accurate.Copyright © 1995-2015 Webtide. All Rights Reserved.