//
//  ========================================================================
//  Copyright (c) 1995-2020 Mort Bay Consulting Pty Ltd and others.
//  ========================================================================
//  All rights reserved. This program and the accompanying materials
//  are made available under the terms of the Eclipse Public License v1.0
//  and Apache License v2.0 which accompanies this distribution.
//
//      The Eclipse Public License is available at
//      http://www.eclipse.org/legal/epl-v10.html
//
//      The Apache License v2.0 is available at
//      http://www.opensource.org/licenses/apache2.0.php
//
//  You may elect to redistribute this code under either of these licenses.
//  ========================================================================
//

[[continuations-using]]
=== Using Continuations

Asynchronous servlets were originally introduced with Jetty 6 Continuations, which were a Jetty specific mechanism.
From Jetty 7 onwards, the Continuations API has been extended to be a general purpose API that will work asynchronously on any servlet-3.0 container, as well as on Jetty 6, 7, or 8.
Continuations will also work in blocking mode with any servlet 2.5 container.

==== Obtaining a Continuation

The link:{JDURL}/org/eclipse/jetty/continuation/ContinuationSupport.html[ContinuationSupport] factory class can be used to obtain a continuation instance associated with a request:

`Continuation continuation = ContinuationSupport.getContinuation(request);`

==== Suspending a Request

To suspend a request, the suspend method can be called on the continuation:

[source, java, subs="{sub-order}"]
----
    void doGet(HttpServletRequest request, HttpServletResponse response)
      {
      ...
      // optionally:
      // continuation.setTimeout(long);
      continuation.suspend();
      ...
      }

----

The lifecycle of the request will be extended beyond the return to the  container from the `Servlet.service(...)` method and `Filter.doFilter(...)` calls. When these dispatch methods return, the suspended request will not yet be committed and a response will not yet be sent to the HTTP client.

Once the request has been suspended, the continuation should be registered with an asynchronous service so that it may be used by an asynchronous callback when the waited-for event happens.

The request will be suspended until either `continuation.resume()` or `continuation.complete()` is called. If neither is called then the continuation will timeout.
The timeout should be set before the suspend, by a call to `continuation.setTimeout(long)` if no timeout is set, then the default period is used.
If no timeout listeners resume or complete the continuation, then the continuation is resumed with `continuation.isExpired()` true.

Suspension is analogous to the servlet 3.0 `request.startAsync()` method. Unlike jetty 6 continuations, an exception is not thrown by suspend and the method should return normally.
This allows the registration of the continuation to occur after suspension and avoids the need for a mutex.
If an exception is desirable (to bypass code that is unaware of continuations and may try to commit the response), then `continuation.undispatch()` may be called to exit the current thread from the current dispatch by throwing a `ContinuationThrowable`.

==== Resuming a Request

Once an asynchronous event has occurred, the continuation can be resumed:

[source, java, subs="{sub-order}"]
----
    void myAsyncCallback(Object results)
    {
    continuation.setAttribute("results",results);
    continuation.resume();
    }
----

When a continuation is resumed, the request is re-dispatched to the servlet container, almost as if the request had been received again.
However during the re-dispatch, the `continuation.isInitial()` method returns false and any attributes set by the asynchronous handler are available.

Continuation resume is analogous to Servlet 3.0 `AsyncContext.dispatch()`.

==== Completing a Request

As an alternative to resuming a request, an asynchronous handler may  write the response itself. After writing the response, the handler must indicate the request handling is complete by calling the complete method:

[source, java, subs="{sub-order}"]
----
    void myAsyncCallback(Object results)
    {
      writeResults(continuation.getServletResponse(),results);
      continuation.complete();
    }
----

After complete is called, the container schedules the response to be  committed and flushed. Continuation complete is analogous to Servlet 3.0 `AsyncContext.complete()`.

==== Continuation Listeners

An application may monitor the status of a continuation by using a ContinuationListener:

[source, java, subs="{sub-order}"]
----
    void doGet(HttpServletRequest request, HttpServletResponse response)
    {
      ...

      Continuation continuation = ContinuationSupport.getContinuation(request);
      continuation.addContinuationListener(new ContinuationListener()
      {
        public void onTimeout(Continuation continuation) { ... }
        public void onComplete(Continuation continuation) { ... }
      });

      continuation.suspend();
      ...
    }
----

Continuation listeners are analogous to Servlet 3.0 AsyncListeners.
