Class EventSource

  • All Implemented Interfaces:
    java.io.Closeable, java.lang.AutoCloseable

    public class EventSource
    extends java.lang.Object
    implements java.io.Closeable
    The SSE client.

    By default, EventSource makes HTTP requests using OkHttp, but it can be configured to read from any input stream. See ConnectStrategy and HttpConnectStrategy.

    Instances are always configured and constructed with EventSource.Builder. The client is created in an inactive state.

    The client uses a pull model where the caller starts the EventSource and then requests data from it synchronously on a single thread. The initial connection attempt is made when you call start(), or when you first attempt to read an event. To read events from the stream, you can either request them one at a time by calling readMessage() or readAnyEvent(), or consume them in a loop by calling messages() or anyEvents(). The "message" methods assume you are only interested in MessageEvent data, whereas the "anyEvent" methods also provide other kinds of stream information. These are blocking methods with no timeout; if you need a timeout mechanism, consider reading from the stream on a worker thread and using a queue such as BlockingQueue to consume the messages elsewhere.

    If, instead of managing your own thread to read from the stream, you would like to have events pushed to you from a worker thread that the library maintains, use BackgroundEventSource.

    Note that although EventSource is named after the JavaScript API that is described in the SSE specification, its behavior is not necessarily identical to standard web browser implementations of EventSource: by default, it will automatically retry (with a backoff delay) for some error conditions where a browser will not retry, and it also supports request configuration options (such as request headers and method) that the browser EventSource does not support. However, its interpretation of the stream data is fully conformant with the SSE specification, unless you use the opt-in mode EventSource.Builder.streamEventData(boolean) which allows for greater efficiency in some use cases but has some behavioral constraints.

    • Method Detail

      • getOrigin

        public java.net.URI getOrigin()
        Returns the stream URI.
        Returns:
        the stream URI
        Since:
        4.0.0
      • getState

        public ReadyState getState()
        Returns an enum indicating the current status of the connection.
        Returns:
        a ReadyState value
      • getLastEventId

        public java.lang.String getLastEventId()
        Returns the ID value, if any, of the last known event.

        This can be set initially with EventSource.Builder.lastEventId(String), and is updated whenever an event is received that has an ID. Whether event IDs are supported depends on the server; it may ignore this value.

        Returns:
        the last known event ID, or null
        Since:
        2.0.0
        See Also:
        EventSource.Builder.lastEventId(String)
      • getNextRetryDelayMillis

        public long getNextRetryDelayMillis()
        Returns the retry delay that will be used for the next reconnection, if the stream has failed.

        If you have just received a StreamException or FaultEvent, this value tells you how long EventSource will sleep before reconnecting, if you tell it to reconnect by calling start() or by trying to read another event. The value is computed by applying the configured RetryDelayStrategy to the current value of getBaseRetryDelayMillis().

        At any other time, the value is undefined.

        Returns:
        the next retry delay in milliseconds
        Since:
        4.0.0
        See Also:
        getBaseRetryDelayMillis()
      • start

        public void start()
                   throws StreamException
        Attempts to start the stream if it is not already active.

        If there is not an active stream connection, this method attempts to start one using the previously configured parameters. If successful, it returns and you can proceed to read events. You should only read events on the same thread where you called start().

        If the connection fails, the behavior depends on the configured ErrorStrategy. The default strategy is to throw a StreamException, but you can configure it to continue instead, in which case start() will keep retrying until the ErrorStrategy says to give up.

        If the stream was previously active and then failed, start() will sleep for some amount of time-- the retry delay-- before trying to make the connection. The retry delay is determined by several factors: see EventSource.Builder.retryDelay(long, TimeUnit), EventSource.Builder.retryDelayStrategy(RetryDelayStrategy), and EventSource.Builder.retryDelayResetThreshold(long, TimeUnit).

        Throws:
        StreamException -

        You do not necessarily need to call this method; it is implicitly called if you try to read an event when the stream is not active. Call it only if you specifically want to confirm that the stream is active before you try to read an event.

        If the stream is already active, calling this method has no effect.

        StreamException - if the connection attempt failed
      • readMessage

        public MessageEvent readMessage()
                                 throws StreamException
        Attempts to receive a message from the stream.

        If the stream is not already active, this calls start() to establish a connection.

        As long as the stream is active, the method blocks until a message is available. If the stream fails, the default behavior is to throw a StreamException, but you can configure an ErrorStrategy to allow the client to retry transparently instead.

        This method must be called from the same thread that first started using the stream (that is, the thread that called start() or read the first event).

        Returns:
        an SSE message
        Throws:
        StreamException - if there is an error and retry is not enabled
        Since:
        4.0.0
        See Also:
        readAnyEvent(), messages()
      • readAnyEvent

        public StreamEvent readAnyEvent()
                                 throws StreamException
        Attempts to receive an event of any kind from the stream.

        This is similar to readMessage(), except that instead of specifically requesting a MessageEvent it also applies to the other subclasses of StreamEvent: StartedEvent, FaultEvent, and CommentEvent. Use this method if you want to be informed of any of those occurrences.

        The error behavior is the same as readMessage(), except that if the ErrorStrategy is configured to let the client continue with an automatic retry, you will receive a FaultEvent describing the error first, and then a StartedEvent once the stream is reconnected.

        This method must be called from the same thread that first started using the stream (that is, the thread that called start() or read the first event).

        Returns:
        an event
        Throws:
        StreamException - if there is an error and retry is not enabled
        Since:
        4.0.0
        See Also:
        readMessage(), anyEvents()
      • messages

        public java.lang.Iterable<MessageEvent> messages()
        Returns an iterable sequence of SSE messages.

        This is similar to calling readMessage() in a loop. If the stream has not already been started, it also starts the stream.

        The error behavior is different from readMessage(): if an error occurs and the ErrorStrategy does not allow the client to continue, it simply stops iterating, rather than throwing an exception. If you need to be able to specifically detect errors, use readMessage().

        This method must be called from the same thread that first started using the stream (that is, the thread that called start() or read the first event).

        Returns:
        a sequence of SSE messages
        Since:
        4.0.0
        See Also:
        readAnyEvent(), messages()
      • anyEvents

        public java.lang.Iterable<StreamEvent> anyEvents()
        Returns an iterable sequence of events.

        This is similar to calling readAnyEvent() in a loop. If the stream has not already been started, it also starts the stream.

        The error behavior is different from readAnyEvent(): if an error occurs and the ErrorStrategy does not allow the client to continue, it simply stops iterating, rather than throwing an exception. If you need to be able to specifically detect errors, use readAnyEvent() (or, use the ErrorStrategy mechanism to cause errors to be reported as FaultEvents).

        This method must be called from the same thread that first started using the stream (that is, the thread that called start() or read the first event).

        Returns:
        a sequence of events
        Since:
        4.0.0
        See Also:
        readAnyEvent(), messages()
      • interrupt

        public void interrupt()
        Stops the stream connection if it is currently active.

        Unlike the reading methods, you are allowed to call this method from any thread. If you are reading events on a different thread, and automatic retries are not enabled by an ErrorStrategy, the other thread will receive a StreamClosedByCallerException.

        The difference between this method and stop() is only relevant if automatic retries are enabled. In this case, if you are using the messages() or anyEvents() iterator to read events, calling interrupt() will cause the stream to be closed and then immediately reconnected, whereas stop() will close it and then the iterator will end. In either case, if you explicitly try to read another event it will start the stream again.

        If the stream is not currently active, calling this method has no effect.

        Note for Android developers: since it is generally undesirable to perform any network activity from the main thread, be aware that interrupt(), stop(), and close() all cause an immediate close of the connection (if any), which happens on the same thread that called the method.

        Since:
        4.0.0
        See Also:
        stop(), start()
      • stop

        public void stop()
        Stops the stream connection if it is currently active.

        Unlike the reading methods, you are allowed to call this method from any thread. If you are reading events on a different thread, and automatic retries are not enabled by an ErrorStrategy, the other thread will receive a StreamClosedByCallerException.

        The difference between this method and interrupt() is only relevant if automatic retries are enabled. In this case, if you are using the messages() or anyEvents() iterator to read events, calling interrupt() will cause the stream to be closed and then immediately reconnected, whereas stop() will close it and then the iterator will end. In either case, if you explicitly try to read another event it will start the stream again.

        If the stream is not currently active, calling this method has no effect.

        Note for Android developers: since it is generally undesirable to perform any network activity from the main thread, be aware that interrupt(), stop(), and close() all cause an immediate close of the connection (if any), which happens on the same thread that called the method.

        Since:
        4.0.0
        See Also:
        interrupt(), start()
      • close

        public void close()
        Permanently shuts down the EventSource.

        This is similar to stop() except that it also releases any resources that the EventSource was maintaining in general, such as an HTTP connection pool. Do not try to use the EventSource after closing it.

        Note for Android developers: since it is generally undesirable to perform any network activity from the main thread, be aware that interrupt(), stop(), and close() all cause an immediate close of the connection (if any), which happens on the same thread that called the method.

        Specified by:
        close in interface java.lang.AutoCloseable
        Specified by:
        close in interface java.io.Closeable
      • awaitClosed

        public boolean awaitClosed​(long timeout,
                                   java.util.concurrent.TimeUnit timeUnit)
                            throws java.lang.InterruptedException
        Blocks until all underlying threads have terminated and resources have been released.
        Parameters:
        timeout - maximum time to wait for everything to shut down, in whatever time unit is specified by timeUnit
        timeUnit - the time unit, or TimeUnit.MILLISECONDS if null
        Returns:
        true if all thread pools terminated within the specified timeout, false otherwise
        Throws:
        java.lang.InterruptedException - if this thread is interrupted while blocking