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
    Modifier and Type | Field and Description
    --- | ---
    `static String` | `ATTRIBUTE`

  - ### Method Summary

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

Copyright © 1995-2015 Mort Bay Consulting. All Rights Reserved.