<?xml version="1.0"?>
<!--

    DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.

    Copyright (c) 2012-2014 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
    http://glassfish.java.net/public/CDDL+GPL_1_1.html
    or packager/legal/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 packager/legal/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.

-->
<!DOCTYPE chapter [<!ENTITY % ents SYSTEM "jersey.ent" > %ents; ]>
<chapter xmlns="http://docbook.org/ns/docbook"
         version="5.0"
         xml:lang="en"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xmlns:xi="http://www.w3.org/2001/XInclude"
         xmlns:xlink="http://www.w3.org/1999/xlink"
         xsi:schemaLocation="http://docbook.org/ns/docbook http://docbook.org/xml/5.0/xsd/docbook.xsd
                             http://www.w3.org/1999/xlink http://www.w3.org/1999/xlink.xsd"
         xml:id="sse">

    <title>Server-Sent Events (SSE) Support</title>

    <section>
        <title>What are Server-Sent Events</title>

        <para>
            In a standard HTTP request-response scenario a client opens a connection, sends a HTTP request to the server (for
            example a HTTP &lit.http.GET; request), then receives a HTTP response back and the server closes the connection once
            the response is fully sent/received. The initiative <emphasis>always</emphasis> comes from a client when the client
            requests all the data. In contrast, <emphasis>Server-Sent Events (SSE)</emphasis> is a mechanism that allows server
            to asynchronously push the data from the server to the client once the client-server connection is established by the
            client. Once the connection is established by the client, it is the server who provides the data and decides
            to send it to the client whenever new "chunk" of data is available. When a new data event occurs on the server,
            the data event is sent by the server to the client. Thus the name Server-Sent Events. Note that at high level there
            are more technologies working on this principle, a short overview of the technologies supporting server-to-client
            communication is in this list:

            <variablelist>
                <varlistentry>
                    <term>Polling</term>
                    <listitem>
                        <para>
                            With polling a client repeatedly sends new requests to a server. If the server has no new data,
                            then it send appropriate indication and closes the connection. The client then waits a bit and sends
                            another request after some time (after one second, for example).
                        </para>
                    </listitem>
                </varlistentry>
                <varlistentry>
                    <term>Long-polling</term>
                    <listitem>
                        <para>
                            With long-polling a client sends a request to a server. If the server has no new data,
                            it just holds the connection open and waits until data is available. Once the server has data
                            (message) for the client, it uses the connection and sends it back to the client. Then the connection
                            is closed.
                        </para>
                    </listitem>
                </varlistentry>
                <varlistentry>
                    <term>Server-Sent events</term>
                    <listitem>
                        <para>
                            SSE is similar to the long-polling mechanism, except it does not send only one message per connection.
                            The client sends a request and server holds a connection until a new message is ready, then it sends
                            the message back to the client while still keeping the connection open so that it can be used
                            for another message once it becomes available. Once a new message is ready, it is sent back to the
                            client on the same initial connection. Client processes the messages sent back from the server
                            individually without closing the connection after processing each message.
                            So, SSE typically reuses one connection for more messages (called events). SSE also defines a
                            dedicated media type that describes a simple format of individual events sent from the server to the
                            client. SSE also offers standard javascript client API implemented most modern browsers. For more
                            information about SSE, see the
                            <link xlink:href='http://www.w3.org/TR/2009/WD-eventsource-20091029/'>SSE API specification</link>.
                        </para>
                    </listitem>
                </varlistentry>
                <varlistentry>
                    <term>WebSocket</term>
                    <listitem>
                        <para>
                            WebSocket technology is different from previous technologies as it provides a real full duplex
                            connection. The initiator is again a client which sends a request to a server with a special HTTP
                            header that informs the server that the HTTP connection may be "upgraded" to a full duplex TCP/IP
                            WebSocket connection. If server supports WebSocket, it may choose to do so. Once a WebSocket
                            connection is established, it can be used for bi-directional communication between the client and the
                            server. Both client and server can then send data to the other party at will whenever it is needed.
                            The communication on the new WebSocket connection is no longer based on HTTP protocol and can be
                            used for example for for online gaming or any other applications that require fast exchange of small
                            chunks of data in flowing in both directions.
                        </para>
                    </listitem>
                </varlistentry>
            </variablelist>
        </para>
    </section>

    <section>
        <title>When to use Server-Sent Events</title>

        <para>
            As explained above, SSE is a technology that allows clients to subscribe to event notifications that originate on
            a server. Server generates new events and sends these events back to the clients subscribed to receive the
            notifications. In other words, SSE offers a solution for a one-way publish-subscribe model.
        </para>
        <para>
            A good example of the use case where SSE can be used is a simple message exchange RESTful service. Clients
            &lit.http.POST; new messages to the service and subscribe to receive messages from other clients.
            Let's call the resource <literal>messages</literal>. While &lit.http.POST;ing a new message to this resource involves
            a typical HTTP request-response communication between a client and the <literal>messages</literal> resource,
            subscribing to receive all new message notifications would be hard and impractical to model with a sequence of
            standard request-response message exchanges. Using Server-sent events provides a much more practical approach here.
            You can use SSE to let clients subscribe to the <literal>messages</literal> resource via standard &lit.http.GET;
            request (use a SSE client API, for example javascript API or Jersey Client SSE API) and let the server broadcast
            new messages to all connected clients in the form of individual events (in our case using Jersey Server SSE API).
            Note that with Jersey a SSE support is implemented as an usual JAX-RS resource method. There's no need to do anything
            special to provide a SSE support in your Jersey/JAX-RS applications, your SSE-enabled resources are a standard part of
            your RESTful Web application that defines the REST API of your application. The following chapters describes SSE
            support in Jersey in more details.
        </para>
        <important>
            <para>
                Note, that while SSE in Jersey is supported with standard JAX-RS resources, Jersey SSE APIs are not part of
                the JAX-RS specification. SSE support and related APIs are a Jersey specific feature that extends JAX-RS.
            </para>
        </important>
    </section>

    <section xml:id="overview">
        <title>Jersey Server-Sent Events API</title>
        <para>
            This chapter briefly describes the Jersey support for SSE. Details and examples will be covered
            in chapters below.
        </para>
        <para>
            Jersey contains support for SSE for both - server and client. SSE in Jersey is implemented as an extension
            supporting a new media type, which means that SSE really treated as just another media type that can be returned from
            a resource method and processed by the client. There is only a minimal additional support for "chunked" messages
            added to Jersey which could not be implemented as standard JAX-RS media type extension.
        </para>
        <para>
            Before you start working with Jersey SSE, in order to add support for SSE you need to include the dependency to the
            <emphasis>SSE media type module</emphasis>:
            <example xml:id="sse.dependency">
                <title>Add <literal>jersey-media-sse</literal> dependency.</title>
                <programlisting language="xml" linenumbering="numbered"><![CDATA[<dependency>
    <groupId>org.glassfish.jersey.media</groupId>
    <artifactId>jersey-media-sse</artifactId>
</dependency>]]></programlisting>
            </example>
            <note>
                <para>
                    Prior to Jersey 2.8, you had to manually register &jersey.sse.SseFeature; in your application.
                    (The &lit.jersey.sse.SseFeature; is a feature that can be registered for both, the client and the server.)
                    Since Jersey 2.8, the feature gets automatically discovered and registered when Jersey SSE module is
                    put on the application's classpath. The automatic discovery and registration of SSE feature can be suppressed
                    by setting &jersey.sse.SseFeature.DISABLE_SSE; property to <literal>true</literal>.
                    The behavior can also be selectively suppressed in either client or server runtime by setting
                    &jersey.sse.SseFeature.DISABLE_SSE_CLIENT; or &jersey.sse.SseFeature.DISABLE_SSE_SERVER; property
                    respectively.
                </para>
            </note>
        </para>
        <para>
            &lit.jersey.sse.SseFeature; adds new supported entity (representation) Java types, namely &jersey.sse.OutboundEvent;
            for the outbound server events and &jersey.sse.InboundEvent; for inbound client events. These types are serialized by
            &lit.jersey.sse.OutboundEventWriter; and de-serialized by &lit.jersey.sse.InboundEventReader;.
            There is no restriction for a media type used in individual event messages; however the media type used for a SSE
            stream as whole is <emphasis>"text/event-stream"</emphasis> and this media type should be set on messages that
            are used to serve SSE events (for example on the server side using &jaxrs.Produces; on the method that returns an
            &lit.jersey.sse.EventOutput; - see below).
            The &lit.jersey.sse.InboundEvent; and &lit.jersey.sse.OutboundEvent; contain all the fields needed for composing
            and processing individual SSE events. These entities represent the <emphasis>chunks</emphasis> sent or received over
            an open server-to-client connection that is represented by an &jersey.server.ChunkedOutput; on the servers side and
            &jersey.client.ChunkedInput; on the client side (if you are not familiar with
            &lit.jersey.server.ChunkedOutput; and &lit.jersey.client.ChunkedInput;, see the
            <link linkend="async">Async chapter</link> first for more details). In other words, our resource method that is used
            to open a SSE connection to a client does not return individual &lit.jersey.sse.OutboundEvent;s. Instead, a new
            instance of &jersey.sse.EventOutput; is returned. &lit.jersey.sse.EventOutput; is a typed extension of
            <literal>ChunkedOutput&lt;OutboundEvent&gt;</literal>. Similarly, to receive &lit.jersey.sse.InboundEvent;s on a
            client side, Jersey SSE API provides a &lit.jersey.sse.EventInput; that represents a typed extension of
            <literal>ChunkedInput&lt;InboundEvent&gt;</literal>.
        </para>
        <para>
            The Jersey server SSE API also contains a &jersey.sse.SseBroadcaster; utility, that provides a convenient way of
            grouping multiple &lit.jersey.sse.EventOutput; instances that represent individual client connections into a
            group, and exposes methods for broadcasting new events to all the client connections grouped in the broadcaster.
            The &lit.jersey.sse.SseBroadcaster; inherits from &jersey.server.Broadcaster; which is the generic broadcaster
            implementation of the Jersey chunked message processing facility.
            On the client side, the Jersey SSE API contains additional &jersey.sse.EventSource; and &jersey.sse.EventListener;
            classes that further improve convenience of processing new inbound SSE events.
        </para>
    </section>

    <section>
        <title>Implementing SSE support in a JAX-RS resource</title>
        <section>
            <title>Simple SSE resource method</title>
            <para>
                Firstly you need to add a <link linkend="sse.dependency">Jersey SSE module dependency</link> to your project
                as shown in the earlier section and register the &jersey.sse.SseFeature; from this module in your
                &jaxrs.core.Application; or &jersey.server.ResourceConfig;. Once done, you are ready to add SSE support
                to your resource:

                <example xml:id="example-simple-sse">
                    <title>Simple SSE resource method</title>
                    <programlisting language="java" linenumbering="numbered">...
import org.glassfish.jersey.media.sse.EventOutput;
import org.glassfish.jersey.media.sse.OutboundEvent;
import org.glassfish.jersey.media.sse.SseFeature;
...

@Path("events")
public static class SseResource {

    @GET
    @Produces(SseFeature.SERVER_SENT_EVENTS)
    public EventOutput getServerSentEvents() {
        final EventOutput eventOutput = new EventOutput();
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    for (int i = 0; i &lt; 10; i++) {
                        // ... code that waits 1 second
                        final OutboundEvent.Builder eventBuilder
                        = new OutboundEvent.Builder();
                        eventBuilder.name("message-to-client");
                        eventBuilder.data(String.class,
                            "Hello world " + i + "!");
                        final OutboundEvent event = eventBuilder.build();
                        eventOutput.write(event);
                    }
                } catch (IOException e) {
                    throw new RuntimeException(
                        "Error when writing the event.", e);
                } finally {
                    try {
                        eventOutput.close();
                    } catch (IOException ioClose) {
                        throw new RuntimeException(
                            "Error when closing the event output.", ioClose);
                    }
                }
            }
        }).start();
        return eventOutput;
    }
}</programlisting>
                </example>

                The code above defines the resource deployed on URI <literal>"/events"</literal>. This resource has a single
                &jaxrs.GET; resource method which returns as an entity &jersey.sse.EventOutput; - an extension of generic Jersey
                &jersey.server.ChunkedOutput; API for output chunked message processing.
                <note>
                    <para>
                        If you are not familiar with
                        &lit.jersey.server.ChunkedOutput; and &lit.jersey.client.ChunkedInput;, see the
                        <link linkend="async">Async chapter</link> first for more details.
                    </para>
                </note>
                After the <literal>eventOutput</literal> is returned from the method, the Jersey runtime recognizes that this is
                a &lit.jersey.server.ChunkedOutput; extension and does not close the client connection immediately. Instead, it
                writes the HTTP headers to the response stream and waits for more chunks (SSE events) to be sent. At this point
                the client can read headers and starts listening for individual events.
                <note>
                    <para>
                        Since Jersey runtime does not implicitly close the connection to the client (similarly to asynchronous
                        processing), closing the connection is a responsibility of the resource method or the client listening
                        on the open connection for new events (see following example).
                    </para>
                </note>
            </para>
            <para>
                In the <xref linkend="example-simple-sse" />, the resource method creates a new thread that sends a sequence of
                10 events. There is a 1 second delay between two subsequent events as indicated in a comment. Each event is
                represented by &lit.jersey.sse.OutboundEvent; type and is built with a helpf of an outbound event
                <literal>Builder</literal>. The &lit.jersey.sse.OutboundEvent; reflects the standardized format of SSE messages
                and contains properties that represent <literal>name</literal> (for named
                events), <literal>comment</literal>, <literal>data</literal> or <literal>id</literal>. The code also sets the
                event data media type using the <literal>mediaType(MediaType)</literal> method on the
                <literal>eventBuilder</literal>. The media type, together with the data type set by the
                <literal>data(Class, Object></literal> method (in our case <literal>String.class</literal>), is used
                for serialization of the event data. Note that the event data media type will not be written to any headers as
                the response <literal>Content-type</literal> header is already defined by the &lit.jaxrs.Produces; and set to
                <literal>"text/event-stream"</literal> using constant from the &lit.jersey.sse.SseFeature;.
                The event media type is used for serialization of event <literal>data</literal>. Event data media type and Java
                type are used to select the proper &jaxrs.ext.MessageBodyWriter; for event data serialization and are passed
                to the selected writer that serializes the event <literal>data</literal> content. In our case the string
                <literal>"Hello world " + i + "!"</literal> is serialized as <literal>"text/plain"</literal>. In event
                <literal>data</literal> you can send any Java entity and associate it with any media type that you would be able
                to serialize with an available &lit.jaxrs.ext.MessageBodyWriter;. Typically, you may want to send e.g. JSON data,
                so you would fill the <literal>data</literal> with a JAXB annotated bean instance and define media type to JSON.
                <note>
                    <para>
                        If the event media type is not set explicitly, the <literal>"text/plain"</literal> media type is used
                        by default.
                    </para>
                </note>
            </para>
            <para>
                Once an outbound event is ready, it can be written to the <literal>eventOutput</literal>. At that point the event
                is serialized by internal &lit.jersey.sse.OutboundEventWriter; which uses an appropriate
                &lit.jaxrs.ext.MessageBodyWriter; to serialize the <literal>"Hello world " + i + "!"</literal> string. You can
                send as many messages as you like. At the end of the thread execution the response is closed which also closes
                the connection to the client. After that, no more messages can be sent to the client on this connection. If the
                client would like to receive more messages, it would have to send a new request to the server to initiate a
                new SSE streaming connection.
            </para>
            <para>
                A client connecting to our SSE-enabled resource will receive the following data from the entity stream:

                <screen language="text" linenumbering="unnumbered">event: message-to-client
data: Hello world 0!

event: message-to-client
data: Hello world 1!

event: message-to-client
data: Hello world 2!

event: message-to-client
data: Hello world 3!

event: message-to-client
data: Hello world 4!

event: message-to-client
data: Hello world 5!

event: message-to-client
data: Hello world 6!

event: message-to-client
data: Hello world 7!

event: message-to-client
data: Hello world 8!

event: message-to-client
data: Hello world 9!</screen>

                Each message is received with a delay of one second.
            </para>

            <note>
                <para>
                    If you have worked with streams in JAX-RS, you may wonder what is the difference between
                    &jersey.server.ChunkedOutput; and &jaxrs.core.StreamingOutput;.
                </para>
                <para>
                    &lit.jersey.server.ChunkedOutput; is Jersey-specific API. It lets you send "chunks" of data without closing
                    the client connection using series of convenient calls to <literal>ChunkedOutput.write</literal> methods
                    that take POJO + chunk media type as an input and then use the configured JAX-RS
                    &lit.jaxrs.ext.MessageBodyWriter; providers to figure out the proper way of serializing each chunk POJO
                    to bytes. Additionally, &lit.jersey.server.ChunkedOutput; writes can be invoked multiple times on the same
                    outbound response connection, i.e. individual chunks are written in each write, not the full response entity.
                </para>
                <para>
                    &lit.jaxrs.core.StreamingOutput; is, on the other hand, a low level JAX-RS API that works with bytes
                    directly. You have to implement &lit.jaxrs.core.StreamingOutput; interface yourself. Also, its
                    <literal>write(OutputStream)</literal> method will be invoked by JAX-RS runtime only once per response
                    and the call to this method is blocking, i.e. the method is expected to write the entire entity body
                    before returning.
                </para>
            </note>
        </section>

        <section>
            <title>Broadcasting with Jersey SSE</title>

            <para>
                Jersey SSE server API defines &jersey.sse.SseBroadcaster; which allows to broadcast individual events to multiple
                clients. A simple broadcasting implementation is shown in the following example:

                <example>
                    <title>Broadcasting SSE messages</title>
                    <programlisting language="java" linenumbering="numbered">...
import org.glassfish.jersey.media.sse.SseBroadcaster;
...

@Singleton
@Path("broadcast")
public static class BroadcasterResource {

    private SseBroadcaster broadcaster = new SseBroadcaster();

    @POST
    @Produces(MediaType.TEXT_PLAIN)
    @Consumes(MediaType.TEXT_PLAIN)
    public String broadcastMessage(String message) {
        OutboundEvent.Builder eventBuilder = new OutboundEvent.Builder();
        OutboundEvent event = eventBuilder.name("message")
            .mediaType(MediaType.TEXT_PLAIN_TYPE)
            .data(String.class, message)
            .build();

        broadcaster.broadcast(event);

        return "Message '" + message + "' has been broadcast.";
    }

    @GET
    @Produces(SseFeature.SERVER_SENT_EVENTS)
    public EventOutput listenToBroadcast() {
        final EventOutput eventOutput = new EventOutput();
        this.broadcaster.add(eventOutput);
        return eventOutput;
    }
}</programlisting>
                </example>

                Let's explore the example together. The <literal>BroadcasterResource</literal> resource class is annotated with
                &jee6.inject.Singleton; annotation which tells Jersey runtime that only a single instance of the resource
                class should be used to serve all the incoming requests to <literal>/broadcast</literal> path. This is needed as
                we want to keep an application-wide single reference to the private <literal>broadcaster</literal> field so that
                we can use the same instance for all requests. Clients that want to listen to SSE events first send a
                &lit.http.GET; request to the <literal>BroadcasterResource</literal>, that is handled by the
                <literal>listenToBroadcast()</literal> resource method.
                The method creates a new &lit.jersey.sse.EventOutput; representing the connection to the requesting client
                and registers this <literal>eventOutput</literal> instance with the singleton <literal>broadcaster</literal>,
                using its <literal>add(EventOutput)</literal> method. The method then returns the <literal>eventOutput</literal>
                which causes Jersey to bind the <literal>eventOutput</literal> instance with the requesting client and send the
                response HTTP headers to the client. The client connection remains open and the client is now waiting ready to
                receive new SSE events. All the events are written to the <literal>eventOutput</literal> by
                <literal>broadcaster</literal> later on. This way developers can conveniently handle sending new events to
                all the clients that subscribe to them.
            </para>
            <para>
                When a client wants to broadcast new message to all the clients listening on their SSE connections,
                it sends a &lit.http.POST; request to <literal>BroadcasterResource</literal> resource with the message content.
                The method <literal>broadcastMessage(String)</literal> is invoked on <literal>BroadcasterResource</literal>
                resource with the message content as an input parameter. A new SSE outbound event is built in the standard way
                and passed to the broadcaster. The broadcaster internally invokes <literal>write(OutboundEvent)</literal> on all
                registered &lit.jersey.sse.EventOutput;s. After that the method just return a standard text response
                to the &lit.http.POST;ing client to inform the client that the message was successfully broadcast. As you can see,
                the <literal>broadcastMessage(String)</literal> resource method is just a simple JAX-RS resource method.
            </para>
            <para>
                In order to implement such a scenario, you may have noticed, that the Jersey  &lit.jersey.sse.SseBroadcaster;
                is not mandatory to complete the use case. individual &jersey.sse.EventOutput;s can be just stored in a collection
                and iterated over in the <literal>broadcastMessage</literal> method. However, the &lit.jersey.sse.SseBroadcaster;
                internally identifies and handles also client disconnects. When a client closes the connection the broadcaster
                detects this and removes the stale connection from the internal collection of the registered
                &jersey.sse.EventOutput;s as well as it frees all the server-side resources associated with the stale connection.
                Additionally, the &lit.jersey.sse.SseBroadcaster; is implemented to be thread-safe, so that clients can connect
                and disconnect in any time and &lit.jersey.sse.SseBroadcaster; will always broadcast messages to the most recent
                collection of registered and active set of clients.
            </para>
        </section>
    </section>

    <section>
        <title>Consuming SSE events with Jersey clients</title>

        <para>
            On the client side, Jersey exposes APIs that support receiving and processing SSE events using two programming models:

            <simplelist>
                <member>Pull model - pulling events from a &jersey.sse.EventInput;, or</member>
                <member>Push model - listening for asynchronous notifications of &lit.jersey.sse.EventSource;</member>
            </simplelist>

            Both models will be described.
        </para>
        <section>
            <title>Reading SSE events with &lit.jersey.sse.EventInput;</title>
            <para>
                The events can be read on the client side from a &jersey.sse.EventInput;. See the following code:

                <programlisting language="java" linenumbering="numbered">Client client = ClientBuilder.newBuilder()
        .register(SseFeature.class).build();
WebTarget target = client.target("http://localhost:9998/events");

EventInput eventInput = target.request().get(EventInput.class);
while (!eventInput.isClosed()) {
    final InboundEvent inboundEvent = eventInput.read();
    if (inboundEvent == null) {
        // connection has been closed
        break;
    }
    System.out.println(inboundEvent.getName() + "; "
        + inboundEvent.readData(String.class));
}</programlisting>

                In this example, a client connects to the server where the <literal>SseResource</literal> from the
                <xref linkend="example-simple-sse" /> is deployed. At first, a new JAX-RS/Jersey <literal>client</literal>
                instance is created with a &lit.jersey.sse.SseFeature; registered. Then a &jaxrs.client.WebTarget; instance is
                retrieved from the <literal>client</literal> and is used to invoke a HTTP request. The returned response entity
                is directly read as a &lit.jersey.sse.EventInput; Java type, which is an extension of Jersey
                &lit.jersey.client.ChunkedInput; that provides generic support for consuming chunked message payloads. The
                code in the example then process starts a loop to process the inbound SSE events read from the
                <literal>eventInput</literal> response stream. Each chunk read from the input is a &lit.jersey.sse.InboundEvent;.
                The method <literal>InboundEvent.readData(Class)</literal> provides a way for the client to indicate what Java type
                should be used for the event data de-serialization. In our example, individual events are de-serialized as
                 <literal>String</literal> Java type instances. This method internally finds and executes a proper
                &jaxrs.ext.MessageBodyReader; which is the used to do the actual de-serialization. This is similar to reading an
                entity from the &jaxrs.core.Response; by <literal>readEntity(Class)</literal>. The method
                <literal>readData</literal> can also throw a &jaxrs.ProcessingException;.
            </para>
            <para>
                The &lit.null; check on <literal>inboundEvent</literal> is necessary to make sure that the chunk was properly
                read and connection has not been closed by the server. Once the connection is closed, the loop terminates and
                the program completes execution. The client code produces the following console output:

                <screen language="text" linenumbering="unnumbered">message-to-client; Hello world 0!
message-to-client; Hello world 1!
message-to-client; Hello world 2!
message-to-client; Hello world 3!
message-to-client; Hello world 4!
message-to-client; Hello world 5!
message-to-client; Hello world 6!
message-to-client; Hello world 7!
message-to-client; Hello world 8!
message-to-client; Hello world 9!</screen>
            </para>
        </section>

        <section>
            <title>Asynchronous SSE processing with &lit.jersey.sse.EventSource;</title>

            <para>
                The main Jersey SSE client API component used to read SSE events asynchronously is &jersey.sse.EventSource;.
                The usage of the &lit.jersey.sse.EventSource; is shown on the following example.
                <example xml:id="sse.ex.client.eventListener">
                    <title>Registering &lit.jersey.sse.EventListener; with &lit.jersey.sse.EventSource;</title>
                    <programlisting language="java" linenumbering="numbered">Client client = ClientBuilder.newBuilder()
                        .register(SseFeature.class).build();
WebTarget target = client.target("http://example.com/events");
EventSource eventSource = EventSource.target(target).build();
EventListener listener = new EventListener() {
        @Override
        public void onEvent(InboundEvent inboundEvent) {
            System.out.println(inboundEvent.getName() + "; "
                    + inboundEvent.readData(String.class));
        }
    };
eventSource.register(listener, "message-to-client");
eventSource.open();
...
eventSource.close();</programlisting>
                </example>

                In this example, the client code again connects to the server where the <literal>SseResource</literal> from the
                <xref linkend="example-simple-sse" /> is deployed. The &jaxrs.client.Client; instance
                is again created and initialized with &jersey.sse.SseFeature;. Then the &jaxrs.client.WebTarget; is built.
                In this case a request to the web target is not made directly in the code, instead, the web target instance
                is used to initialize a new &jersey.sse.EventSource.Builder; instance that is used to build a new
                &lit.jersey.sse.EventSource;. The choice of <literal>build()</literal> method is important, as it tells
                the &lit.jersey.sse.EventSource.Builder; to create a new &lit.jersey.sse.EventSource; that is not automatically
                connected to the <literal>target</literal>. The connection is established only later by manually invoking
                the <literal>eventSource.open()</literal> method. A custom &jersey.sse.EventListener;
                implementation is used to listen to and process incoming SSE events. The method readData(Class) says that the
                event data should be de-serialized from a received &jersey.sse.InboundEvent; instance into a
                <literal>String</literal> Java type. This method call internally executes &jaxrs.ext.MessageBodyReader; which
                de-serializes the event data. This is similar to reading an entity from the &jaxrs.core.Response; by
                <literal>readEntity(Class)</literal>. The method <literal>readData</literal> can throw a
                &jaxrs.ProcessingException;.
            </para>
            <para>
                The custom event source listener is registered in the event source via
                &lit.jersey.sse.EventSource;<literal>.register(EventListener, String)</literal> method. The next method
                arguments define the names of the events to receive and can be omitted. If names are defined, the listener
                will be associated with the named events and will only invoked for events with a name from the set of defined
                event names. It will not be invoked for events with any other name or for events without a name.

                <important>
                    <para>
                        It is a common mistake to think that unnamed events will be processed by listeners that are registered
                        to process events from a particular name set. That is NOT the case! Unnamed events are only processed
                        by listeners that are not name-bound. The same limitation applied to HTML5 Javascript SSE Client API
                        supported by modern browsers.
                    </para>
                </important>

                After a connection to the server is opened by calling the <literal>open()</literal> method on the event source,
                the <literal>eventSource</literal> starts listening to events. When an event named
                <literal>"message-to-client"</literal> comes, the listener will be executed by the event source. If any other
                event comes (with a name different from <literal>"message-to-client"</literal>), the registered listener is not
                invoked. Once the client is done with processing and does not want to receive events anymore, it closes the
                connection by calling the <literal>close()</literal> method on the event source.
            </para>
            <para>
                The listener from the example above will print the following output:
                <screen language="text" linenumbering="unnumbered">message-to-client; Hello world 0!
message-to-client; Hello world 1!
message-to-client; Hello world 2!
message-to-client; Hello world 3!
message-to-client; Hello world 4!
message-to-client; Hello world 5!
message-to-client; Hello world 6!
message-to-client; Hello world 7!
message-to-client; Hello world 8!
message-to-client; Hello world 9!</screen>
            </para>
            <para>
                When browsing through the Jersey SSE API documentation, you may have noticed that the &jersey.sse.EventSource;
                implements &jersey.sse.EventListener; and provides an empty implementation for the
                <literal>onEvent(InboundEvent inboundEvent)</literal> listener method. This adds more flexibility to the
                Jersey client-side SSE API. Instead of defining and registering a separate event listener, in simple scenarios
                you can also choose to derive directly from the &lit.jersey.sse.EventSource; and override the empty listener
                method to handle the incoming events. This programming model is shown in the following example:

                <example>
                    <title>Overriding <literal>EventSource.onEvent(InboundEvent)</literal> method</title>
                    <programlisting language="java" linenumbering="numbered">Client client = ClientBuilder.newBuilder()
                        .register(SseFeature.class).build();
WebTarget target = client.target("http://example.com/events");
EventSource eventSource = new EventSource(target) {
    @Override
    public void onEvent(InboundEvent inboundEvent) {
        if ("message-to-client".equals(inboundEvent.getName())) {
            System.out.println(inboundEvent.getName() + "; "
                    + inboundEvent.readData(String.class));
        }
    }
};
...
eventSource.close();</programlisting>
                </example>

                The code above is very similar to the code in <xref linkend="sse.ex.client.eventListener" />. In this example
                however, the &lit.jersey.sse.EventSource; is constructed directly using a single-parameter constructor.
                This way, the connection to the SSE endpoint is by default automatically opened at the event source
                creation. The implementation of the &lit.jersey.sse.EventListener; has been moved into the overridden
                <literal>EventSource.onEvent(...)</literal> method. However, this time, the listener method will be executed for
                all events - unnamed as well as with any <literal>name</literal>. Therefore the code checks the name whether it is
                an event with the name "message-to-client" that we want to handle. Note that you can still register
                additional &lit.jersey.sse.EventListener;s later on. The overridden method on the event source allows you to
                handle messages even when no additional listeners are registered yet.
            </para>

            <section>
                <title>&lit.jersey.sse.EventSource; reconnect support</title>
                <para>
                    Starting in Jersey 2.3, the &lit.jersey.sse.EventSource; implementation supports automated recuperation
                    from a connection loss, including negotiation of delivery of any missed events based on the last received
                    SSE event <literal>id</literal> field value, provided this field is set by the server and the negotiation
                    facility is supported by the server. In case of a connection loss, the last received SSE event
                    <literal>id</literal> field value is send in the <literal>Last-Event-ID</literal> HTTP request
                    header as part of a new connection request sent to the SSE endpoint. Upon a receipt of such reconnect request,
                    the SSE endpoint that supports this negotiation facility is expected to replay all missed events.
                </para>
                <note>
                    <para>
                        Note, that SSE lost event negotiation facility is a best-effort mechanism which does not provide
                        any guaranty that all events would be delivered without a loss. You should therefore not
                        rely on receiving every single event and design your client application code accordingly.
                    </para>
                </note>
                <para>
                    By default, when a connection the the SSE endpoint is lost, the event source will use a default delay
                    before attempting to reconnect to the SSE endpoint. The SSE endpoint can however control the client-side
                    retry delay by including a special <literal>retry</literal> field value in any event sent to the client.
                    Jersey &lit.jersey.sse.EventSource; implementation automatically tracks any received SSE event
                    <literal>retry</literal> field values set by the endpoint and adjusts the reconnect delay accordingly,
                    using the last received <literal>retry</literal> field value as the new reconnect delay.
                </para>
                <para>
                    In addition to handling the standard connection losses, Jersey &lit.jersey.sse.EventSource; automatically
                    deals with any <literal>HTTP 503 Service Unavailable</literal> responses received from the SSE endpoint,
                    that include a <literal>Retry-After</literal> HTTP header with a valid value. The
                    <literal>HTTP 503 + Retry-After</literal> technique is often used by HTTP endpoints as a means of
                    connection and traffic throttling. In case a <literal>HTTP 503 + Retry-After</literal> response is received
                    in return to a connection request from SSE endpoint, Jersey <literal>EventSource</literal> will automatically
                    schedule a reconnect attempt  and use the received <literal>Retry-After</literal> HTTP header value as a
                    one-time override of the reconnect delay.
                </para>
            </section>
        </section>
    </section>
</chapter>
