org.eclipse.jetty.continuation

## Interface Continuation

All Known Subinterfaces:
  ContinuationFilter.FilteredContinuation

All Known Implementing Classes:
  AsyncContinuation

    public interface Continuation

Continuation. A continuation is a mechanism by which a HTTP Request can be suspended and restarted after a timeout or an asynchronous event has occurred.

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.

# Continuation Usage

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.

### Suspend/Resume Usage

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));
       }

### Suspend/Complete Usage

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()

# Continuation Timeout

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.

See Also:
  `ContinuationSupport`, `ContinuationListener`

### Field Summary

Fields
`static String` `ATTRIBUTE`

### Method Summary

Methods
`void` `addContinuationListener(ContinuationListener listener)` Add a ContinuationListener.
`void` `complete()` Complete a suspended request.
`Object` `getAttribute(String name)` Get a request attribute.
`javax.servlet.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(javax.servlet.ServletResponse response)` Suspend the processing of the request and associated `ServletResponse`.
`void` `undispatch()` Undispatch the request.

### Field Detail

#### ATTRIBUTE

    static final String ATTRIBUTE

See Also:
  Constant Field Values

### Method Detail

#### setTimeout

    void setTimeout(long timeoutMs)

Set the continuation timeout.

Parameters:
  `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.

#### suspend

    void suspend()

Suspend the processing of the request and associated `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:

- a call to `resume()`.
- a call to `complete()`.
- the timeout expires.

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.

Throws:
  `IllegalStateException` - If the request cannot be suspended

#### suspend

    void suspend(javax.servlet.ServletResponse response)

Suspend the processing of the request and associated `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:

- a call to `resume()`.
- a call to `complete()`.
- the timeout expires.

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).

Parameters:
  `response` - The response to return via a call to `getServletResponse()`
Throws:
  `IllegalStateException` - If the request cannot be suspended

#### resume

    void resume()

Resume a suspended request.

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.

Throws:
  `IllegalStateException` - if the request is not suspended.
See Also:
  `suspend()`

#### complete

    void complete()

Complete a suspended request.

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.

Throws:
  `IllegalStateException` - if the request is not suspended.
See Also:
  `suspend()`

#### isSuspended

    boolean isSuspended()

Returns:
  true after `suspend()` has been called and before the request has been redispatched due to being resumed, completed or timed out.

#### isResumed

    boolean isResumed()

Returns:
  true if the request has been redispatched by a call to `resume()`. Returns false after any subsequent call to suspend

#### isExpired

    boolean isExpired()

Returns:
  true after a request has been redispatched as the result of a timeout. Returns false after any subsequent call to suspend.

#### isInitial

    boolean isInitial()

Returns:
  true while the request is within the initial dispatch to the filter chain and/or servlet. Will return false once the calling thread has returned to the container after suspend has been called and during any subsequent redispatch.

#### isResponseWrapped

    boolean isResponseWrapped()

Is the suspended response wrapped.

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)`.

Returns:
  True if `suspend(ServletResponse)` has been passed a `ServletResponseWrapper` instance.

#### getServletResponse

    javax.servlet.ServletResponse getServletResponse()

Get the suspended response.

Returns:
  the `ServletResponse` passed to `suspend(ServletResponse)`.

#### addContinuationListener

    void addContinuationListener(ContinuationListener listener)

Add a ContinuationListener.

Parameters:
  `listener` -

#### setAttribute

    void setAttribute(String name,
                    Object attribute)

Set a request attribute. This method is a convenience method to call the `ServletRequest.setAttribute(String, Object)` method on the associated request object. This is a thread safe call and may be called by any thread.

Parameters:
  `name` - the attribute name
  `attribute` - the attribute value

#### getAttribute

    Object getAttribute(String name)

Get a request attribute. This method is a convenience method to call the `ServletRequest.getAttribute(String)` method on the associated request object. This is a thread safe call and may be called by any thread.

Parameters:
  `name` - the attribute name
Returns:
  the attribute value

#### removeAttribute

    void removeAttribute(String name)

Remove a request attribute. This method is a convenience method to call the `ServletRequest.removeAttribute(String)` method on the associated request object. This is a thread safe call and may be called by any thread.

Parameters:
  `name` - the attribute name

#### undispatch

    void undispatch()
                    throws ContinuationThrowable

Undispatch the request.

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.

This method should only be used as a last resort and a normal return is a prefereable solution if filters can be updated to handle that case.

Throws:
  `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.