public abstract class Sse extends Object implements AutoCloseable
Server-Sent Events (SSE) is a mechanism that allows server to 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.
{
sse("/path", sse -> {
// 1. connected
sse.send("data"); // 2. send/push data
});
}
Simple, effective and easy to use. The callback will be executed once when a new client is connected. Inside the callback we can send data, listen for connection close events, etc.
There is a factory method event(Object)
that let you set event attributes:
{
sse("/path", sse -> {
sse.event("data")
.id("id")
.name("myevent")
.retry(5000L)
.send();
});
}
Beside raw/string data you can also send structured data, like json
,
xml
, etc..
The next example will send two message one in json
format and one in
text/plain
format:
{
use(new MyJsonRenderer());
sse("/path", sse -> {
MyObject object = ...
sse.send(object, "json");
sse.send(object, "plain");
});
}
Or if your need only one format, just:
{
use(new MyJsonRenderer());
sse("/path", sse -> {
MyObject object = ...
sse.send(object);
}).produces("json"); // by default always send json
}
We provide request access via two arguments callback:
{
sse("/events/:id", (req, sse) -> {
String id = req.param("id").value();
MyObject object = findObject(id);
sse.send(object);
});
}
The #onClose(CheckedRunnable)
callback allow you to clean and release resources on
connection close. A connection is closed by calling close()
or when the client/browser
close the connection.
{
sse("/events/:id", sse -> {
sse.onClose(() -> {
// clean up resources
});
});
}
The close event will be generated if you try to send an event on a closed connection.
The keep alive time feature can be used to prevent connections from timing out:
{
sse("/events/:id", sse -> {
sse.keepAlive(15, TimeUnit.SECONDS);
});
}
The previous example will sent a ':'
message (empty comment) every 15 seconds to
keep the connection alive. If the client drop the connection, then the
#onClose(CheckedRunnable)
event will be fired it.
This feature is useful when you want to detect #onClose(CheckedRunnable)
events without
waiting for the next time you send a new event. But for example, if your application already
generate events every 15s, then the use of keep alive is useless and you can avoid it.
The require(Class)
methods let you access to application services:
{
sse("/events/:id", sse -> {
MyService service = sse.require(MyService.class);
});
}
The next example will generate a new event every 60s. It recovers from a server shutdown by using
the lastEventId()
and clean resources on connection close.
{
// creates an executor service
ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);
sse("/events", sse -> {
// if we go down, recover from last event ID we sent. Otherwise, start from zero.
int lastId = sse.lastEventId(Integer.class).orElse(0);
AtomicInteger next = new AtomicInteger(lastId);
// send events every 60s
ScheduledFuture<?> future = executor.scheduleAtFixedRate(() -> {
Integer id = next.incrementAndGet();
Object data = findDataById(id);
// send data and id
sse.event(data).id(id).send();
}, 0, 60, TimeUnit.SECONDS);
// on connection lost, cancel 60s task
sse.onClose(() -> {
future.cancel(true);
});
});
}
Modifier and Type | Class and Description |
---|---|
static class |
Sse.Event
Event representation of Server sent event.
|
static interface |
Sse.Handler
Server-sent event handler.
|
static interface |
Sse.Handler1
Single argument event handler.
|
Modifier and Type | Field and Description |
---|---|
protected org.slf4j.Logger |
log
The logging system.
|
Constructor and Description |
---|
Sse() |
Modifier and Type | Method and Description |
---|---|
void |
close()
Close the connection and fire an
#onClose(CheckedRunnable) event. |
protected abstract void |
closeInternal() |
Sse.Event |
event(Object data)
Factory method for creating
Sse.Event instances. |
protected void |
fireCloseEvent() |
protected void |
handshake(Request req,
Runnable handler) |
protected abstract void |
handshake(Runnable handler) |
String |
id()
A unique ID (like a session ID).
|
protected void |
ifClose(Throwable cause) |
Sse |
keepAlive(int time,
TimeUnit unit)
The keep alive time can be used to prevent connections from timing out:
|
Sse |
keepAlive(long millis)
The keep alive time can be used to prevent connections from timing out:
|
Optional<String> |
lastEventId()
Server sent event will send a Last-Event-ID header if the server goes down.
|
<T> Optional<T> |
lastEventId(Class<T> type)
Server sent event will send a Last-Event-ID header if the server goes down.
|
Sse |
onClose(javaslang.control.Try.CheckedRunnable task)
Listen for connection close (usually client drop the connection).
|
<T> T |
require(Class<T> type)
Ask Guice for the given type.
|
<T> T |
require(com.google.inject.Key<T> key)
Ask Guice for the given type.
|
<T> T |
require(String name,
Class<T> type)
Ask Guice for the given type.
|
<T> T |
require(com.google.inject.TypeLiteral<T> type)
Ask Guice for the given type.
|
javaslang.concurrent.Future<Optional<Object>> |
send(Object data)
Send an event.
|
javaslang.concurrent.Future<Optional<Object>> |
send(Object data,
MediaType type)
Send an event and set media type.
|
javaslang.concurrent.Future<Optional<Object>> |
send(Object data,
String type)
Send an event and set media type.
|
protected abstract javaslang.concurrent.Promise<Optional<Object>> |
send(Optional<Object> id,
byte[] data) |
protected boolean |
shouldClose(Throwable ex) |
protected void handshake(Request req, Runnable handler) throws Exception
Exception
public String id()
public Optional<String> lastEventId()
public <T> Optional<T> lastEventId(Class<T> type)
T
- Event id type.type
- Last event id type.public Sse onClose(javaslang.control.Try.CheckedRunnable task)
task
- Task to run.public javaslang.concurrent.Future<Optional<Object>> send(Object data, String type)
sse.send(new MyObject(), "json");
On success the Future.onSuccess(java.util.function.Consumer)
callback will be executed:
sse.send(new MyObject(), "json").onSuccess(id -> {
//
});
The id
of the success callback correspond to the Sse.Event.id()
.
On error the Future.onFailure(java.util.function.Consumer)
callback will be executed:
sse.send(new MyObject(), "json").onFailure(cause -> {
//
});
data
- Event data.type
- Media type, like: json, xml.Sse.Event.id()
.public javaslang.concurrent.Future<Optional<Object>> send(Object data, MediaType type)
sse.send(new MyObject(), "json");
On success the Future.onSuccess(java.util.function.Consumer)
callback will be executed:
sse.send(new MyObject(), "json").onSuccess(id -> {
//
});
The id
of the success callback correspond to the Sse.Event.id()
.
On error the Future.onFailure(java.util.function.Consumer)
callback will be executed:
sse.send(new MyObject(), "json").onFailure(cause -> {
//
});
data
- Event data.type
- Media type, like: json, xml.Sse.Event.id()
.public javaslang.concurrent.Future<Optional<Object>> send(Object data)
sse.send(new MyObject());
On success the Future.onSuccess(java.util.function.Consumer)
callback will be executed:
sse.send(new MyObject()).onSuccess(id -> {
//
});
The id
of the success callback correspond to the Sse.Event.id()
.
On error the Future.onFailure(java.util.function.Consumer)
callback will be executed:
sse.send(new MyObject()).onFailure(cause -> {
//
});
data
- Event data.Sse.Event.id()
.public Sse.Event event(Object data)
Sse.Event
instances.
Please note event won't be sent unless you call Sse.Event.send()
:
sse.event(new MyObject()).send();
The factory allow you to set event attributes:
// send data
MyObject data = ...;
sse.event(data).send();
// send data with event name
sse.event(data).name("myevent").send();
// send data with event name and id
sse.event(data).name("myevent").id(id).send();
// send data with event name, id and retry interval
sse.event(data).name("myevent").id(id).retry(1500).send();
data
- Event data.public <T> T require(Class<T> type)
T
- Service type.type
- A service type.public <T> T require(String name, Class<T> type)
T
- Service type.name
- A service name.type
- A service type.public <T> T require(com.google.inject.TypeLiteral<T> type)
T
- Service type.type
- A service type.public <T> T require(com.google.inject.Key<T> key)
T
- Service type.key
- A service key.public Sse keepAlive(int time, TimeUnit unit)
{
sse("/events/:id", sse -> {
sse.keepAlive(15, TimeUnit.SECONDS);
});
}
The previous example will sent a ':'
message (empty comment) every 15 seconds to
keep the connection alive. If the client drop the connection, then the
#onClose(CheckedRunnable)
event will be fired it.
This feature is useful when you want to detect #onClose(CheckedRunnable)
events without
waiting until you send a new event. But for example, if your application already generate
events
every 15s, then the use of keep alive is useless and you should avoid it.
time
- Keep alive time.unit
- Time unit.public Sse keepAlive(long millis)
{
sse("/events/:id", sse -> {
sse.keepAlive(15, TimeUnit.SECONDS);
});
}
The previous example will sent a ':'
message (empty comment) every 15 seconds to
keep the connection alive. If the client drop the connection, then the
#onClose(CheckedRunnable)
event will be fired it.
This feature is useful when you want to detect #onClose(CheckedRunnable)
events without
waiting until you send a new event. But for example, if your application already generate
events
every 15s, then the use of keep alive is useless and you should avoid it.
millis
- Keep alive time in millis.public final void close() throws Exception
#onClose(CheckedRunnable)
event.close
in interface AutoCloseable
Exception
protected abstract void closeInternal()
protected abstract javaslang.concurrent.Promise<Optional<Object>> send(Optional<Object> id, byte[] data)
protected void ifClose(Throwable cause)
protected void fireCloseEvent()
protected boolean shouldClose(Throwable ex)
Copyright © 2017. All rights reserved.