---
slug: java-server-events-client
title: Java Server Events Client
---

The Java `ServerEventClient` is an idiomatic port of ServiceStack's
[C# Server Events Client](/csharp-server-events-client) to Java providing a productive
client to consume ServiceStack's [real-time Server Events](/server-events) that can be used in any
Java/JVM (JRE 7+) Client/Server Applications or Java/Kotlin Android applications.
## Install
The `AndroidServerEventsClient` for Android is available in the
[net.servicestack:android](https://bintray.com/servicestack/maven/ServiceStack.Android) package which
can be installed in your
[build.gradle](https://github.com/ServiceStackApps/AndroidJavaChat/blob/master/src/androidchat/app/build.gradle)
with:
```groovy
dependencies {
implementation 'net.servicestack:android:1.1.0'
...
}
```
Or in Maven with:
```xml
net.servicestack
android
1.1.0
pom
```
Other Java/JVM languages running on the JVM (JRE 7+) can use the `ServerEventsClient` in the
[net.servicestack:client](https://bintray.com/servicestack/maven/ServiceStack.Client) package which can
be installed using Gradle:
```
compile 'net.servicestack:client:1.0.48'
```
Or Maven:
```xml
net.servicestack
client
1.0.48
pom
```
The `AndroidServerEventsClient` class for Android inherits `ServerEventsClient` to provide enhanced
functionality like alternative non-blocking APIs for all Sync APIs using Android Async Tasks. It also requires
the use of an external [OkHttp Client](http://square.github.io/okhttp/) dependency since the
`HttpURLConnection` implementation in Android doesn't support cancellable non-blocking requests on HTTP Streams. Otherwise both implementations provide the same functionality and are interchangeable, for the
purposes of demonstration we'll be using `AndroidServerEventsClient`.
To configure Server Sent Events on the client create a new instance of `AndroidServerEventsClient` with the
**baseUrl** and the **channels** you want to connect to, e.g:
```java
ServerEventsClient client = new AndroidServerEventsClient(baseUrl, "home")
.setOnConnect(sub -> { // Successful SSE connection
Log.d("You've connected! welcome " + sub.getDisplayName());
})
.setOnJoin(e -> { // User has joined subscribed channel
Log.d("Welcome, " + e.getDisplayName());
})
.setOnLeave(e -> { // User has left subscribed channel
Log.d(e.getDisplayName() + " has left the building");
})
.setOnUpdate(e -> { // User channel subscription was changed
Log.d(e.getDisplayName() + " has left the building");
})
.setOnMessage(msg -> { }) // Invoked for each other message
//... Register custom handlers
.registerHandler("chat", (client, e) -> { // Invoked for cmd.chat adhoc messages
ChatMessage chatMsg = JsonUtils.fromJson(e.getJson(), ChatMessage.class);
})
.registerReceiver(MyReceiver.class) // Register Global 'cmd.' default receiver
.registerNamedReceiver("tv",TvReceiver.class) // Register named 'tv.' receiver
.addListener("theEvent", msg -> {}) // Add listener for pub/sub event trigger
.setOnException(e -> { }) // Invoked on each Error
.setOnReconnect(() -> { }) // Invoked after each auto-reconnect
.start(); // Start listening for Server Events!
//Global Receiver Class
public class MyReceiver extends ServerEventReceiver {
public void announce(String message){} // Handle messages with simple argument
public void chat(ChatMessage message){} // Handle messages with complex type argument
public void customType(CustomType message){} // Handle complex types with default selector
@Override // Handle other unknown messages
public void noSuchMethod(String selector, Object message){}
}
//Named Receiver Class
public class TvReciever extends ServerEventReceiver {
public void watch(String videoUrl){} // Handle 'tv.watch {url}' messages
public void off(){} // Handle 'tv.off' messages
}
```
### Message Events
ServiceStack Server Events has 4 built-in events sent during a subscriptions life-cycle:
- **onConnect** - sent when successfully connected, includes the subscriptions private `subscriptionId` as well as heartbeat and unregister urls that's used to automatically setup periodic heartbeats
- **onJoin** - sent when a new user joins the channel
- **onLeave** - sent when a user leaves the channel
- **onUpdate** - sent when a user's channels subscription was updated
> The onJoin/onLeave/onUpdate events can be turned off with `ServerEventsFeature.NotifyChannelOfSubscriptions=false`.
All other messages can be handled with the catch-all:
- **onMessage** - fired when any other message is sent
### Server Event Client Events
Other top-level events the `ServerEventClient` fires that can be handled include:
- **onException** - Invoked on each error the client receives
- **onReconnect** - Invoked after each time the client had to auto-reconnect
## Selectors
A selector is a string that identifies what should handle the message, it's used by the client to route the message to different handlers. The client bindings supports 4 different handlers out of the box:
### Global Event Handlers
The easiest way to handle a custom event is to define a handler, e.g:
```java
ServerEventsClient client = new AndroidServerEventsClient(baseUrl, "home")
.registerHandler("paint", (client, e) -> {
String color = JsonUtils.fromJson(e.getJson(), String.class);
Log.d("Painting the " + e.getCssSelector() + " " + color);
})
.registerHandler("chat", (client, e) -> {
ChatMessage chatMsg = JsonUtils.fromJson(e.getJson(), ChatMessage.class);
Log.d("Received " + chatMsg.getMessage() + " from " + chatMsg.getFromName());
})
.start();
```
The selector to invoke a global event handler is:
```
cmd.{handler} {message}
```
Which can be sent in ServiceStack with:
```csharp
ServerEvents.NotifyChannel("home", "cmd.paint$#town", "red");
ServerEvents.NotifyChannel("home", "cmd.chat", new ChatMessage { ... });
```
Where `{handler}` is the name of the handler you want to invoke, e.g `cmd.paint`. The first argument is
the `ServerEventsClient` instance whilst the 2nd argument a structured `ServerEventMessage` which for
the above Server Event is populated with:
```java
.registerHandler("paint", (client, e) -> {
e.getChannel() //= home
e.getData() //= home@cmd.paint$#town "red"
e.getSelector() //= cmd.paint
e.getJson() //= "red"
e.getOp() //= cmd
e.getTarget() //= paint
e.getCssSelector() //= #town
})
```
The message body is serialized as JSON and accessible from `e.getJson()` and can be extracted using `JsonUtils`,e.g:
```java
String color = JsonUtils.fromJson(e.getJson(), String.class); //Simple string message body
ChatMessage chatMsg = JsonUtils.fromJson(e.getJson(), ChatMessage.class); //Complex Type body
```
### Postfix CSS selector
All server event handler options also support a postfix CSS selector for specifying what each handler should be bound to with a `$` followed by the CSS selector, e.g:
```
cmd.{handler}${cssSelector} {value}
```
A concrete example for calling the above API would be:
```
cmd.paint$#town red
```
::: info
Spaces in CSS selectors need to be encoded with `%20`
:::
#### Handling Messages with the Default Selector
All `IServerEvents` Notify API's includes [overloads for sending messages without a selector](https://github.com/ServiceStack/ServiceStack/blob/master/src/ServiceStack/ServerEventsFeature.cs#L743-L771) that by convention will take the format `cmd.{TypeName}`.
As they're prefixed with `cmd.*` these events can be handled with either a handler (as above) or a global receiver **based on Message type name**, e.g:
```java
ServerEventsClient client = new AndroidServerEventsClient(baseUrl, "home")
.registerReceiver(MyGlobalReceiver.class)
.start();
public class TestGlobalReceiver extends ServerEventReceiver {
public void setterType(SetterType value) {
}
public void customType(CustomType request) {
}
}
```
Which will be called when messages are sent without a selector, e.g:
```csharp
public class MyServices : Service
{
public IServerEvents ServerEvents { get; set; }
public void Any(Request request)
{
ServerEvents.NotifyChannel("home", new CustomType { ... });
ServerEvents.NotifyChannel("home", new SetterType { ... });
}
}
```
Whilst Named Receivers are used to handle messages sent to a specific namespaced selector, registering a
**Global Receiver** allows you to handle messages sent with the `cmd.*` selector which is also the default
selector used when sending messages with **no selector**.
### Receivers
In programming languages based on message-passing like Smalltalk and Objective-C invoking a method is done by sending a message to a receiver. This is conceptually equivalent to invoking a method on an instance in C# where both these statements are roughly equivalent:
```objc
// Objective-C
[receiver method:argument]
```
```csharp
// C#
receiver.method(argument)
```
Support for receivers is available in the following format:
```
{receiver}.{target} {msg}
```
### Registering Receivers
Registering a receiver can be done with a map of the object instance and the name you want it to be exported as. E.g. we can add a "css" receiver to handle with:
```java
ServerEventsClient client = new AndroidServerEventsClient(baseUrl, "home")
.registerNamedReceiver("css", CssReceiver.class)
.setResolver(new MyResolver(mainActivity))
.start();
public class CssReceiver extends ServerEventReceiver {
private MainActivity parentActivity;
public CssReceiver(MainActivity parentActivity) {
this.parentActivity = parentActivity;
}
public void backgroundImage(String message){
String url = message.startsWith("url(")
? message.substring(4, message.length() - 1)
: message;
App.get().readBitmap(url, bitmap -> {
ImageView chatBackground = (ImageView)parentActivity.findViewById(R.id.chat_background);
parentActivity.runOnUiThread(() -> chatBackground.setImageBitmap(bitmap));
});
}
public void background(String message){
String color = message.replace("#", "#AA");
String cssSelector = super.getRequest().getCssSelector();
parentActivity.runOnUiThread(() -> {
if (Objects.equals(cssSelector, "#top")){
parentActivity.getSupportActionBar().setBackgroundDrawable(
new ColorDrawable(colorVal)
);
}
});
}
}
public class MyResolver implements IResolver {
private MainActivity parentActivity;
public MyResolver(MainActivity parentActivity) {
this.parentActivity = parentActivity;
}
@Override
public Object TryResolve(Class cls){
if (cls == CssReceiver.class){
return new CssReceiver(this.parentActivity);
}
return cls.newInstance();
}
}
```
Which will invoke `backgroundImage` method off a new instance of the `CssReceiver` class that's triggered with:
```
css.background-image url(https://bit.ly/1yIJOBH)
```
and can be sent to all subscriptions on the **home** channel in ServiceStack with:
```csharp
ServerEvents.NotifyChannel("home", "css.background-image", "url(https://bit.ly/1yIJOBH)");
```
This works the same with Global Receivers.
### Inheriting ServerEventReceiver
By inheriting `ServerEventReceiver`:
```java
class ServerEventReceiver implements IReceiver {
public client: ServerEventsClient;
public request: ServerEventMessage;
noSuchMethod(selector: string, message:any) {}
}
```
Receivers can access additional built-in functionality where it will allow receivers to access the
`ServerEventsClient` client dependency, the `ServerEventMessage` that was received, it also lets you handle
any unhandled messages sent by implementing `noSuchMethod()`, e.g:
```java
class JavaScriptReceiver extends ServerEventReceiver {
public void chat(ChatMessage chatMessage){
LogMessage request = new LogMessage()
.setChannel(msg.getChannel())
.setMessage(msg.getMessage());
super.client.getServiceClient().post(request);
}
public void announce(String message){
Toast.makeText(this.parentActivity, message, Toast.LENGTH_LONG);
}
public void toggle(){
if ("#sidebar".equals(super.request.getCssSelector())){
LinearLayout sidebarLayout=(LinearLayout)this.findViewById(R.id.sidebarLayout);
sidebarLayout.setVisibility(sidebarLayout.getVisibility() == LinearLayout.INVISIBLE
? LinearLayout.VISIBLE
: LinearLayout.INVISIBLE
);
}
}
public void noSuchMethod(String selector, Object message){
ServerEventMessage msg = (ServerEventMessage)message;
Log.d("Unhandled " + selector + " was sent message: " + msg.getJson());
}
}
client.registerReceiver(JavaScriptReceiver.class); //register Global Receiver
```
These can triggered with:
```csharp
ServerEvents.NotifyChannel(channel, new ChatMessage { ... });
ServerEvents.NotifyChannel(channel, "cmd.announce", "Hello, World!");
ServerEvents.NotifyChannel(channel, "cmd.toggle$#sidebar");
ServerEvents.NotifyChannel(channel, "cmd.UnknownSelector", new Message { ... });
```
### Dependency Resolvers
You can control the lifetime of the receivers by injecting a custom resolver which will let you reuse the same
Receiver instance by using a `SingletonInstanceResolver`, e.g:
```java
ServerEventsClient client = new AndroidServerEventsClient(baseUrl, "home")
.setResolver(new SingletonInstanceResolver())
.registerReceiver(JavaScriptReceiver.class)
.start();
```
Which is implemented with:
```java
public class SingletonInstanceResolver implements IResolver {
ConcurrentMap cache = new ConcurrentHashMap<>();
@Override
public Object TryResolve(Class cls) {
Object instance = cache.get(cls);
if (instance == null){
try {
Object newInstance = cls.newInstance();
instance = (instance = cache.putIfAbsent(cls, newInstance)) == null
? newInstance
: instance;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
return instance;
}
}
```
Custom Resolvers are also useful configuring the dependencies in your Receiver classes, e.g. we use this
above to inject our `MainActivity` into our `CssReceiver` class.
```java
ServerEventsClient client = new AndroidServerEventsClient(baseUrl, "home")
.setResolver(new MyResolver())
.registerReceiver(CssReceiver.class)
.start();
public class MyResolver implements IResolver {
private MainActivity parentActivity;
public MyResolver(MainActivity parentActivity) {
this.parentActivity = parentActivity;
}
@Override
public Object TryResolve(Class cls){
if (cls == CssReceiver.class){
return new CssReceiver(this.parentActivity);
}
return cls.newInstance();
}
}
```
### Event Triggers
Triggers enable a pub/sub event model where multiple listeners can subscribe and be notified of an event.
Registering an event handler can be done at anytime using the `addListener()` API, e.g:
```java
Action handler = e -> {
Log.d("received event " + e.getTarget() + " with arg: " + e.getJson());
};
ServerEventsClient client = new AndroidServerEventsClient(baseUrl, "home")
.addListener("customEvent", handler)
.start();
//Register another listener to 'customEvent' event
List msgs1 = new ArrayList<>();
client.addListener("customEvent", msgs1::add);
```
The selector to trigger this custom event is:
```
trigger.customEvent arg
trigger.customEvent {json}
```
Which can be sent in ServiceStack with a simple or complex type argument, e.g:
```csharp
ServerEvents.NotifyChannel(channel, "trigger.customEvent", "arg");
ServerEvents.NotifyChannel(channel, "trigger.customEvent", new ChatMessage { ... });
```
#### Removing Listeners
Use `removeListener()` to stop listening for an event, e.g:
```java
//Remove first event listener
client.removeListener("customEvent", handler);
```
### Channel Subscriber APIs
You can use any of the APIs below to update an active Subscriptions Channels:
```java
client.subscribeToChannels("chan3","chan4");
client.unsubscribeFromChannels("chan1","chan2");
//Alternatively subscribe/unsubscribe to channels in the same request with:
UpdateEventSubscriber request = new UpdateEventSubscriber()
.setSubscribeChannels(Func.toList("chan3","chan4"))
.setUnsubscribeChannels(Func.toList("chan1","chan2"));
client.updateSubscriber(request);
```
All Service Client APIs in `AndroidServiceClient` also have non-blocking versions with an an `Async` suffix
that utilize Android's Async Task and optional callbacks for performing non-blocking Service Client requests, e.g:
```java
client.updateSubscriberAsync(request, () -> {
Log.d("SUCCESS!");
}, e -> {
Log.d("FAILED: " + e.toString());
});
```
### Get Channel Subscribers
Once connected, you can get a list of channel subscribers the `ServerEventsClient` is currently connected
to with:
```java
List channelUsers = client.getChannelSubscribers();
Func.each(channelUsers, user -> {
Log.d(user.getUserId() + " @" + user.getDisplayName() + " " + user.getProfileUrl());
});
```
### Accessing ServiceClient
Alternatively you can access the channel subscribers using the built-in `JsonServiceClient`, e.g:
```java
client.getServiceClient().get(new GetEventSubscribers()
.setChannels(Func.toList("chan1","chan2")));
```
Which you can also use to call your own Services:
```java
client.getServiceClient().post(new MyRequest());
```
### Integration Test Examples
More examples of `ServerEventClient` usage can be found in the Test Suites below:
- [Java 8 / JVM Integration Tests](https://github.com/ServiceStack/ServiceStack.Java/blob/master/src/AndroidClient/client/src/test/java/net/servicestack/client/ServerEventClientTests.java)
- [Java 7 / Android Integration Tests](https://github.com/ServiceStack/ServiceStack.Java/blob/master/src/AndroidClient/android/src/androidTest/java/net/servicestack/android/ServerEventClientTests.java)
# Java ServerEvents Examples
## [Android Java Chat](https://github.com/ServiceStackApps/AndroidJavaChat)
Java Chat client utilizing [Server Events](/java-server-events-client) for real-time notifications and enabling seamless OAuth Sign In's using Facebook, Twitter and Google's native SDKs:
[](https://github.com/ServiceStackApps/AndroidJavaChat)