Class EventSource
- java.lang.Object
-
- com.launchdarkly.eventsource.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
andHttpConnectStrategy
.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 callingreadMessage()
orreadAnyEvent()
, or consume them in a loop by callingmessages()
oranyEvents()
. The "message" methods assume you are only interested inMessageEvent
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 asBlockingQueue
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 modeEventSource.Builder.streamEventData(boolean)
which allows for greater efficiency in some use cases but has some behavioral constraints.
-
-
Nested Class Summary
Nested Classes Modifier and Type Class Description static class
EventSource.Builder
Builder for configuringEventSource
.
-
Field Summary
Fields Modifier and Type Field Description static int
DEFAULT_READ_BUFFER_SIZE
The default value forEventSource.Builder.readBufferSize(int)
.static long
DEFAULT_RETRY_DELAY_MILLIS
The default value forEventSource.Builder.retryDelay(long, TimeUnit)
: 1 second.static long
DEFAULT_RETRY_DELAY_RESET_THRESHOLD_MILLIS
The default value forEventSource.Builder.retryDelayResetThreshold(long, TimeUnit)
: 60 seconds.
-
Method Summary
All Methods Instance Methods Concrete Methods Modifier and Type Method Description java.lang.Iterable<StreamEvent>
anyEvents()
Returns an iterable sequence of events.boolean
awaitClosed(long timeout, java.util.concurrent.TimeUnit timeUnit)
Blocks until all underlying threads have terminated and resources have been released.void
close()
Permanently shuts down the EventSource.long
getBaseRetryDelayMillis()
Returns the current base retry delay.java.lang.String
getLastEventId()
Returns the ID value, if any, of the last known event.LDLogger
getLogger()
Returns the logger that this EventSource is using.long
getNextRetryDelayMillis()
Returns the retry delay that will be used for the next reconnection, if the stream has failed.java.net.URI
getOrigin()
Returns the stream URI.ReadyState
getState()
Returns an enum indicating the current status of the connection.void
interrupt()
Stops the stream connection if it is currently active.java.lang.Iterable<MessageEvent>
messages()
Returns an iterable sequence of SSE messages.StreamEvent
readAnyEvent()
Attempts to receive an event of any kind from the stream.MessageEvent
readMessage()
Attempts to receive a message from the stream.void
start()
Attempts to start the stream if it is not already active.void
stop()
Stops the stream connection if it is currently active.
-
-
-
Field Detail
-
DEFAULT_RETRY_DELAY_MILLIS
public static final long DEFAULT_RETRY_DELAY_MILLIS
The default value forEventSource.Builder.retryDelay(long, TimeUnit)
: 1 second.- See Also:
- Constant Field Values
-
DEFAULT_RETRY_DELAY_RESET_THRESHOLD_MILLIS
public static final long DEFAULT_RETRY_DELAY_RESET_THRESHOLD_MILLIS
The default value forEventSource.Builder.retryDelayResetThreshold(long, TimeUnit)
: 60 seconds.- See Also:
- Constant Field Values
-
DEFAULT_READ_BUFFER_SIZE
public static final int DEFAULT_READ_BUFFER_SIZE
The default value forEventSource.Builder.readBufferSize(int)
.- See Also:
- Constant Field Values
-
-
Method Detail
-
getOrigin
public java.net.URI getOrigin()
Returns the stream URI.- Returns:
- the stream URI
- Since:
- 4.0.0
-
getLogger
public LDLogger getLogger()
Returns the logger that this EventSource is using.- Returns:
- the logger
- Since:
- 4.0.0
- See Also:
EventSource.Builder.logger(LDLogger)
-
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)
-
getBaseRetryDelayMillis
public long getBaseRetryDelayMillis()
Returns the current base retry delay.This is initially set by
EventSource.Builder.retryDelay(long, TimeUnit)
, orDEFAULT_RETRY_DELAY_MILLIS
if not specified. It can be overriden by the stream provider if the stream contains a "retry:" line.The actual retry delay for any given reconnection is computed by applying the configured
RetryDelayStrategy
to this value.- Returns:
- the base retry delay in milliseconds
- Since:
- 4.0.0
- See Also:
getNextRetryDelayMillis()
-
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
orFaultEvent
, this value tells you how long EventSource will sleep before reconnecting, if you tell it to reconnect by callingstart()
or by trying to read another event. The value is computed by applying the configuredRetryDelayStrategy
to the current value ofgetBaseRetryDelayMillis()
.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 aStreamException
, but you can configure it to continue instead, in which casestart()
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: seeEventSource.Builder.retryDelay(long, TimeUnit)
,EventSource.Builder.retryDelayStrategy(RetryDelayStrategy)
, andEventSource.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 anErrorStrategy
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 aMessageEvent
it also applies to the other subclasses ofStreamEvent
:StartedEvent
,FaultEvent
, andCommentEvent
. 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 theErrorStrategy
is configured to let the client continue with an automatic retry, you will receive aFaultEvent
describing the error first, and then aStartedEvent
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 theErrorStrategy
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, usereadMessage()
.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 theErrorStrategy
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, usereadAnyEvent()
(or, use theErrorStrategy
mechanism to cause errors to be reported asFaultEvent
s).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 aStreamClosedByCallerException
.The difference between this method and
stop()
is only relevant if automatic retries are enabled. In this case, if you are using themessages()
oranyEvents()
iterator to read events, callinginterrupt()
will cause the stream to be closed and then immediately reconnected, whereasstop()
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()
, andclose()
all cause an immediate close of the connection (if any), which happens on the same thread that called the method.
-
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 aStreamClosedByCallerException
.The difference between this method and
interrupt()
is only relevant if automatic retries are enabled. In this case, if you are using themessages()
oranyEvents()
iterator to read events, callinginterrupt()
will cause the stream to be closed and then immediately reconnected, whereasstop()
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()
, andclose()
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()
, andclose()
all cause an immediate close of the connection (if any), which happens on the same thread that called the method.- Specified by:
close
in interfacejava.lang.AutoCloseable
- Specified by:
close
in interfacejava.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 bytimeUnit
timeUnit
- the time unit, orTimeUnit.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
-
-