I have implemented Jersey SSE, My requirement is to send notificaion to connected clients when there is a data chnage on the server.
Well My SSE is working, now I am trying to tie it up with the code in POJO class which detects data chnage.
My resource looks like this
package org.example;
import javax.annotation.PostConstruct;
import javax.ws.rs.*;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.core.UriInfo;
import javax.ws.rs.sse.OutboundSseEvent;
import javax.ws.rs.sse.Sse;
import javax.ws.rs.sse.SseEventSink;
import org.jvnet.hk2.annotations.Service;
@Service
@Path("events")
public class SSEResource {
@Context
Sse sse;
private SSEConnectionManager connectionManager;
@PostConstruct
public void initialize() {
connectionManager = SSEConnectionManager.getInstance();
connectionManager.initialize(sse);
}
@GET
@Produces(MediaType.SERVER_SENT_EVENTS)
public void getServerSentEvents(@Context SseEventSink eventSink, @Context UriInfo uri) {
MultivaluedMap<String, String> queryParams = uri.getQueryParameters();
String closeParam = queryParams.getFirst("close");
String clientIdParam = queryParams.getFirst("clientId");
System.out.println("Client ID Parameter: " + clientIdParam);
// Check if clientIdParam is missing or empty
if (clientIdParam == null || clientIdParam.isEmpty()) {
// Send a message to enter the clientId
sendEventToClient(eventSink, "Please enter a valid clientId!");
// Close the SSE connection since clientId is not provided
eventSink.close();
return; // Return early
}
if (closeParam != null && clientIdParam != null && !clientIdParam.isEmpty()) {
// Close the SSE connection immediately
eventSink.close();
return; // Return early without sending the welcome message
}
// Check if the client has an existing connection
if (connectionManager.isConnected(clientIdParam)) {
connectionManager.closeConnection(clientIdParam);
}
// Add the connection to the SSEConnectionManager
connectionManager.addConnection(clientIdParam, eventSink);
// Send a welcome message to the client
sendEventToClient(eventSink, "Welcome to SSE, Client " + clientIdParam + "!");
}
// Method to send an SSE event to a specific client
private void sendEventToClient(SseEventSink eventSink, String data) {
final OutboundSseEvent event = sse.newEventBuilder().name("message-to-client").data(String.class, data).build();
eventSink.send(event);
}
public void sendEventToSpecificClient(String clientId, String message) {
try {
System.out.println("Client ID Parameter: " + clientId);
if (clientId != null && !clientId.isEmpty()) {
// Check if the client is connected
if (connectionManager.isConnected(clientId)) {
try {
sendEventToClient(connectionManager.getConnection(clientId), message);
} catch (Exception e) {
// Handle any exceptions that occur during sending the event
System.out.println("Error sending event to Client " + clientId + ": " + e.getMessage());
}
} else {
System.out.println("Client " + clientId + " not connected!");
}
}
} finally {
// eventSink.close(); // Close the SseEventSink in the finally block
}
}
@GET
@Path("close/{clientId}")
@Produces(MediaType.TEXT_PLAIN)
public String closeConnection(@PathParam("clientId") String clientId) {
if (clientId != null && !clientId.isEmpty()) {
if (connectionManager.isConnected(clientId)) {
connectionManager.closeConnection(clientId);
return "SSE connection closed for client " + clientId;
} else {
return "Client " + clientId + " not connected!";
}
} else {
return "Invalid client ID!";
}
}
public void broadcastEvent(String message) {
final OutboundSseEvent event = sse.newEventBuilder().name("broadcast").mediaType(MediaType.TEXT_PLAIN_TYPE).data(String.class, message).build();
// Broadcast the event to all connected clients
connectionManager.getBroadcaster().broadcast(event);
}
}
What I want to be able to is to call sendEventToSpecificClient() or broadcastEvent() from my POJO class
For testing sake I created this, but sseResource is always null
import javax.inject.Inject;
public class MainApp {
@Inject
SSEResource sseResource;
public static void main(String[] args) {
// Simulate the client ID and message
String clientId = "123";
String message = "This is a test message.";
new MainApp().call(clientId, message);
}
void call(String clientId, String message) {
// Call the sendEventToSpecificClient method to send the event
sseResource.sendEventToSpecificClient(clientId, message);
}
}
Here's is MyApplication.java
import org.glassfish.hk2.utilities.binding.AbstractBinder;
import org.glassfish.jersey.server.ResourceConfig;
public class MyApplication extends ResourceConfig {
public MyApplication() {
// Register your resource classes or packages here using packages(), register(), etc.
packages("org.example");
// Register the AppLifecycleListener
register(AppLifecycleListener.class);
// Register the AbstractBinder with the bindings for dependency injection
register(new AbstractBinder() {
@Override
protected void configure() {
// Bind the SSEResource class to itself (no need to specify the same class again)
bind(SSEResource.class).to(SSEResource.class);
}
});
}
}
How Can properly inject the SSEresource in normal POJO class? I am using HK2 which comes with jersey.