I am new to using SSE with Jersey, and have the following situation.
I have a JAXB annotated class that represents and acts on the I/O of a Raspberry Pi (class GpioRepresentation).
The client class accesses the status of I/O through the method getUpdate() which returns the XML object representation of the class.
@XmlRootElement
public class GpioRepresentation implements GpioSubject
{
...
/**
* Returns an object of this class with the current
* representation of the I/O states
* @return this
*/
public synchronized GpioRepresentation getUpdate()
{
this.getGarageDoorInputState();
this.getZoneOneFeedback();
this.getZoneTwoFeedback();
this.getZoneThreeFeedback();
this.getGarageDoorRelayState();
this.getZoneOneRelayState();
this.getZoneTwoRelayState();
this.getZoneThreeRelayState();
return this;
}
...
}
The client that uses getUpdate() is the class HomeResource, method getPiStatusStream(). This is a JAX-RS annotated method, and provides remote clients Server Sent Events. Currently this method is written as shown here with a continuous loop in a separate thread which polls for updates.
@Path("/homeservice")
@RolesAllowed({"ADMIN", "USER"})
@Produces(MediaType.APPLICATION_XML)
@Consumes(MediaType.APPLICATION_XML)
public class HomeResource
{
private static final Logger LOGGER = LoggerFactory.getLogger(HomeResource.class);
private GpioRepresentation piService;
...
/**
* gets status information on the Raspberry Pi's
* I/O and returns it to the client on a continuous basis
* and only if it changes.
* @return EventOutput
*/
@GET
@Path("/iostatus")
@Produces(SseFeature.SERVER_SENT_EVENTS)
public EventOutput getPiStatusStream()
{
final EventOutput eventOutput = new EventOutput();
new Thread(new Runnable()
{
public void run()
{
try {
String gdState = null;
String zOneState = null;
String zTwoState = null;
String zThreeState = null;
String gdRState = null;
String zOneRState = null;
String zTwoRState = null;
String zThreeRState = null;
String lastgdState = null;
String lastzOneState = null;
String lastzTwoState = null;
String lastzThreeState = null;
String lastgdRState = null;
String lastzOneRState = null;
String lastzTwoRState = null;
String lastzThreeRState = null;
while(true) {
final OutboundEvent.Builder eventBuilder = new OutboundEvent.Builder();
final GpioRepresentation iostatus = piService.getUpdate();
gdState = piService.getGarageDoorInputState();
zOneState = piService.getZoneOneFeedback();
zTwoState = piService.getZoneTwoFeedback();
zThreeState = piService.getZoneThreeFeedback();
gdRState = piService.getGarageDoorRelayState();
zOneRState = piService.getZoneOneRelayState();
zTwoRState = piService.getZoneTwoRelayState();
zThreeRState = piService.getZoneThreeRelayState();
if (!(gdState.equals(lastgdState) && zOneState.equals(lastzOneState) && zTwoState.equals(lastzTwoState) && zThreeState.equals(lastzThreeState)
&& gdRState.equals(lastgdRState) && zOneRState.equals(lastzOneRState) && zTwoRState.equals(lastzTwoRState) && zThreeRState.equals(lastzThreeRState)))
{
OutboundEvent event = eventBuilder.data(GpioRepresentation.class, iostatus)
.mediaType(MediaType.APPLICATION_XML_TYPE)
.build();
eventOutput.write(event);
lastgdState = gdState;
lastzOneState = zOneState;
lastzTwoState = zTwoState;
lastzThreeState = zThreeState;
lastgdRState = gdRState;
lastzOneRState = zOneRState;
lastzTwoRState = zTwoRState;
lastzThreeRState = zThreeRState;
}
Thread.sleep(100);
}
}
catch (Exception exeption)
{
System.err.println("Error: " + exeption);
}
finally
{
try
{
eventOutput.close();
}
catch (IOException ioClose)
{
throw new RuntimeException("Error when closing the event output.", ioClose);
}
}
}
}).start();
return eventOutput;
}
...
}
The issue I have and see with this is that this doesn't scale well. Creating a thread for every GET from a remote client takes time, and eats CPU resources. Plus I don't think this is an elegant solution. What I would like to do is encapsulate the event code into a separate class, and use some sort of observer pattern that can trigger the creation of an event....however, how do I tie this into the resource method so that it can be returned to the remote client?
Can anyone point me to some examples, or provide advice on designing a solution for this?
Solution was to utilize the SseBroadcaster class. I made the HomeService class an observer of the GpioRepresentation class, and then called a new method (broadcastIOUpdateMessage()) which then output my event to the remote client.
public void broadcastIOUpdateMessage()
{
GpioRepresentation iostatus = piService.getUpdate();
OutboundEvent.Builder eventBuilder = new OutboundEvent.Builder();
OutboundEvent event = eventBuilder.data(GpioRepresentation.class, iostatus)
.mediaType(MediaType.APPLICATION_XML_TYPE)
.build();
broadcaster.broadcast(event);
}
@GET
@Path("/iostatus")
@Produces(SseFeature.SERVER_SENT_EVENTS)
public EventOutput getPiStatusStream()
{
final EventOutput eventOutput = new EventOutput();
this.broadcaster.add(eventOutput);
return eventOutput;
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.