Spring SSEEmitter Getting Completed Mid-way - html

I am new to Server Sent Events but not to Spring.
Have made a controller which gets triggered from a button on the UI which initiates SSEEmitter and passed that to another thread which in loop sends message to UI after each 4 seconds.
SO far i am running a loop of 10 which sleeps for 4 seconds each but suddenly around iteration of 6 or 7th loop, I get exception "Exception in thread "Thread-4" java.lang.IllegalStateException: ResponseBodyEmitter is already set complete"..
Hence, event source again re-establishes the connection i.e. calls the controller method again which certainly i do not want.
I am here trying a simple thing.. User subscribes by clicking on the button..
Server send response 10 or 20 whatever times to the browser. And as far as I think this is what SSE created for.
Code below.:
#RequestMapping("/subscribe")
public SseEmitter subscribe() {
SseEmitter sseEmitter = new SseEmitter();
try {
sseEmitter.send("Dapinder");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Runnable r = new AnotherThread(sseEmitter);
new Thread(r).start();
return sseEmitter;
}
public class AnotherThread implements Runnable {
private SseEmitter sseEmitter;
public AnotherThread(SseEmitter sseEmitter) {
super();
this.sseEmitter = sseEmitter;
}
#Override
public void run() {
SseEventBuilder builder = SseEmitter.event();
builder.name("dapEvent");
for (int i = 0; i < 10; i++) {
builder.data("This is the data: " + i +" time.");
try {
//sseEmitter.send(builder);
sseEmitter.send("Data: "+i);
//sseEmitters.get(1L).send("Hello");
} catch (IOException e) {
e.printStackTrace();
}
try {
Thread.sleep(4000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
sseEmitter.complete();
}
public SseEmitter getSseEmitter() {
return sseEmitter;
}
public void setSseEmitter(SseEmitter sseEmitter) {
this.sseEmitter = sseEmitter;
}
}
function start() {
var eventSource = new EventSource("http://localhost:8080/HTML5SSE/springSSE/subscribe"); // /springSSE/connect
eventSource.onmessage = function(event) {
document.getElementById('foo').innerHTML = event.data;
};
}
<button onclick="start()">Subscribe</button>

Your builder is not being used; you create and configure a builder, but then you send a plain message with 'sseEmitter.send' directly. Try this:
sseEmitter.send(SseEmitter.event().name("dapEvent").data("This " + i +" time.");
One more thing: Why do you call the send method already in the subscribe method? At this point in time, the SseEmitter has not been returned. Is this message coming through to the client?
Here is an excellent article explaining SSE from the JavaScript perspective (not Spring). You will see here that you can cancel the event stream from the client by calling close on the stream. Combine this with an event listener, and you should have what you need:
var source = new EventSource('...');
source.addEventListener('error', function(e) {
if (e.currentTarget.readyState == EventSource.CLOSED) {
// Connection was closed.
} else {
// Close it yourself
source.close();
}
});
source.addEventListener('message', function(e) {
console.log(e.data);
});
Note: The article says e.readyState, however I think this is wrong. The received object e is an Event. You need to get the EventSource object from it like this: e.currentTarget.

You need to use the second constructor of SseEmitter which takes a Long timeout argument. Please refer the code below -
#RequestMapping("/subscribe")
public SseEmitter subscribe() {
SseEmitter sseEmitter = new SseEmitter(Long.MAX_VALUE) // for maximum timeout
Below is the copy of Java-doc of this constructor -
/**
* Create a SseEmitter with a custom timeout value.
* <p>By default not set in which case the default configured in the MVC
* Java Config or the MVC namespace is used, or if that's not set, then the
* timeout depends on the default of the underlying server.
* #param timeout timeout value in milliseconds
* #since 4.2.2
*/
I think the default timeout of SSE connection in Tomcat is 40 seconds. Not sure though.

Related

Infinite wait loading remote image into BitmapImage() in Background Agent

I have a valid URL for a remote JPEG which I'm trying to load in the background. But I find I never get control back after invoking the BitmapImage() constructor. My question is, should this approach work, or should I pitch it all, load up BcpAsync project from NuGet and start working with WebClient asynch methods?
A sample URL for which it fails is
http://image.weather.com/images/maps/current/garden_june_720x486.jpg
It is valid. .UpdateAsync() references it from AppViewModel.Instance, it's not explicitly referenced here.
Here's the background agent:
protected override async void OnInvoke(ScheduledTask task)
{
AppViewModel.LoadData();
await AppViewModel.Instance.RemoteImageProxy.UpdateAsync();
AppViewModel.Instance.ImageUrl = AppViewModel.Instance.RemoteImageProxy.LocalFileUri;
AppViewModel.Instance.UpdateCount++;
PinnedTile.Update();
}
AppViewModel.SaveData();
#if DEBUG
ScheduledActionService.LaunchForTest(task.Name, TimeSpan.FromSeconds(AppViewModel.Instance.BgAgentInterval));
#endif
NotifyComplete();
}
Here's the invoked method:
public Task<double> UpdateAsync() {
LastCheckedTime = DateTime.UtcNow;
CompletionTask = new TaskCompletionSource<double>();
// Not usually called on UI thread, not worth optimizing for that case here.
Deployment.Current.Dispatcher.BeginInvoke(() => { //todo determine whether System.Windows.Deployment.Dispatcher can be called from main app, or just bgAgent.
HelperImageControl = new Image();
HelperImageControl.Loaded += im_Loaded;
HelperImageControl.ImageFailed += im_ImageFailed;
HelperImageControl.ImageOpened += im_ImageOpened;
// breakpoint here
HelperImageControl.Source = new BitmapImage(SourceUri);
// stepping over the function, control does not return here. Nor are any of the above events fired.
});
return CompletionTask.Task; // this will be completed in one of the subsequent control events...
}
You need to call CompletionTask.SetResult(); to return control back to the caller method.
This works (I'm returning 100 in case of successful download because you set the task to return double).
TaskCompletionSource<double> CompletionTask;
public Task<double> UpdateAsync()
{
CompletionTask = new TaskCompletionSource<double>();
Deployment.Current.Dispatcher.BeginInvoke(() =>
{
var HelperImageControl = new Image();
var bmp = new BitmapImage();
bmp.ImageOpened += bmp_ImageOpened;
bmp.ImageFailed += bmp_ImageFailed;
bmp.CreateOptions = BitmapCreateOptions.None;
bmp.UriSource = new Uri("http://image.weather.com/images/maps/current/garden_june_720x486.jpg", UriKind.Absolute);
HelperImageControl.Source = bmp;
});
return CompletionTask.Task;
}
void bmp_ImageFailed(object sender, ExceptionRoutedEventArgs e)
{
CompletionTask.SetException(e.ErrorException);
}
void bmp_ImageOpened(object sender, RoutedEventArgs e)
{
CompletionTask.SetResult(100);
}

Resubmit web requests on resuming from dormancy

I am using RestSharp (a REST client for .NET) in my Windows Phone 8 app, but I think my question also applies using HttpWebRequest or any other ways of running web requests.
I am trying to find a way to automatically resubmit the requests when app is resumed from dormant state. This is only from dormant and not from the tombstone state.
The idea I had was to create a wrapper object which subscribes to the Deactivated event before starting the request and rerunning the request in case it received the event.
I assume that since the deactivated event was received, the request failed.
public class RestClientEx
{
bool wasDeactivated = false;
public async Task<T> ExecuteTaskAsync<T>(RestClient client, RestRequest request) where T : new()
{
var phoneApplicationService = App.Current.ApplicationLifetimeObjects.OfType<PhoneApplicationService>().First();
phoneApplicationService.Deactivated += phoneApplicationService_Deactivated;
var t = await client.ExecuteTaskAsync<T>(request);
if (this.wasDeactivated)
{
// resubmit request
this.wasDeactivated = false;
t = await this.ExecuteTaskAsync<T>(client, request);
}
return t;
}
void phoneApplicationService_Deactivated(object sender, DeactivatedEventArgs e)
{
(sender as PhoneApplicationService).Deactivated -= phoneApplicationService_Deactivated;
this.wasDeactivated = true;
}
}
My question is, is there another way to achieve this?
Is it OK what I am doing?

How to pass execution to the UI thread in a task when having to wait for the result (without Dispatcher) in a Windows Store App?

This is a duplication of my question in the Windows Store Apps Forum:
I have an awaitable method returning a Task. It gets passed a delegate designated to make a decision. The task iterates though some objects and invokes the delegate to determine if an object should be processed. In classic .NET I would implement that as follows:
private Task ProcessDemo(Func<int, bool> processDecisionHandler)
{
// Get the current SynchronizationContext
SynchronizationContext synchronizationContext = SynchronizationContext.Current;
return Task.Run(() =>
{
for (int i = 0; i < 10; i++)
{
// Invoke the process decision handler in the UI thread
bool process = false;
synchronizationContext.Send((state) => { process = processDecisionHandler(i); }, i);
if (process)
{
// Process the item
...
}
}
});
}
This method could be invoked like this:
private async void testButton_Click(object sender, RoutedEventArgs e)
{
this.WriteLine("UI-Thread ({0})", Thread.CurrentThread.ManagedThreadId);
Func<int, bool> handler = (i) =>
{
if (MessageBox.Show("Process " + i + "?", this.Title, MessageBoxButton.YesNo, MessageBoxImage.Information) == MessageBoxResult.Yes)
{
return true;
}
else
{
return false;
}
};
await this.ProcessDemo(handler);
}
In Windows Store Apps I face the problem that the Send method of SynchronizationContext is not available. Post would obviously not work for my goal since I have to "await" the handler result.
How could I achieve my goal anyway without a Dispatcher (that I do not have in library code)?
If it's always invoked from the UI thread, then you can do something like this:
private Task ProcessDemo(Func<int, bool> processDecisionHandler)
{
for (int i = 0; i < 10; i++)
{
// Invoke the process decision handler in the UI thread
if (processDecisionHandler(i))
{
// Process the item on a threadpool thread.
await Task.Run(...);
}
}
}

NullPointerException error on Implementing Location API on J2me

I am trying to implement jsr-179 APi into Nokia Symbian phone for periodic location update using setLocationListener through J2me. In emulator it is working fine. While I installed Midlet on the device nokia 5230, it is given NullPointerException and the application is automatically terminating. What might be possible causes?
Below is my class, I am instantiating object for this class on a form in netbeans
class MovementTracker implements LocationListener {
LocationProvider provider;
Location lastValidLocation;
UpdateHandler handler;
boolean done;
public MovementTracker() throws LocationException
{
done = false;
handler = new UpdateHandler();
new Thread(handler).start();
//Defining Criteria for Location Provider
/*
Criteria cr = new Criteria();
cr.setHorizontalAccuracy(500);
*/
//you can place cr inside getInstance
provider = LocationProvider.getInstance(null);
//listener,interval,timeout,int maxAge
//Passing -1 selects default interval
// provider.setLocationListener(MovementTracker.this, -1, -1, -1);
provider.setLocationListener(MovementTracker.this, -1, 30000, 30000);
}
public void locationUpdated(LocationProvider provider, Location location)
{
handler.handleUpdate(location);
batteryLevel = System.getProperty("com.nokia.mid.batterylevel");
sn = System.getProperty("com.nokia.mid.networksignal");
localTime = System.currentTimeMillis();
Send_Location();
}
public void providerStateChanged(LocationProvider provider, int newState)
{
}
class UpdateHandler implements Runnable
{
private Location updatedLocation = null;
// The run method performs the actual processing of the location
public void run()
{
Location locationToBeHandled = null;
while (!done)
{
synchronized(this)
{
if (updatedLocation == null)
{
try
{
wait();
}
catch (Exception e)
{
// Handle interruption
}
}
locationToBeHandled = updatedLocation;
updatedLocation = null;
}
// The benefit of the MessageListener is here.
// This thread could via similar triggers be
// handling other kind of events as well in
// addition to just receiving the location updates.
if (locationToBeHandled != null)
processUpdate(locationToBeHandled);
}
try
{
Thread.sleep(10000); //Sleeps for 10 sec & then sends the data
}
catch (InterruptedException ex)
{
}
}
public synchronized void handleUpdate(Location update)
{
updatedLocation = update;
notify();
}
private void processUpdate(Location update)
{
latitude = update.getQualifiedCoordinates().getLatitude();
longitude = update.getQualifiedCoordinates().getLongitude();
altitude = update.getQualifiedCoordinates().getAltitude();
}
}
}
public MovementTracker() throws LocationException
...
I have not written any code for handling LocationException.
No code is very dangerous practice, just search the web for something like "java swallow exceptions".
It is quite possible that because of implementation specifics Nokia throws LocationException where emulator does not throw it. Since you don't handle exception this may indeed crash you midlet at Nokia - and you wouldn't know the reason for that because, again, you have written no code to handle it.
How can I catch that exception?
The simplest thing you can do is to display an Alert with exception message and exit the midlet after user reads and dismisses alert

while loop ignore the event listener

so when i run this code to try to change the background the GUI crashes and gets stuck in a infinite while loop ignoring the event listeners. here is the code:
private Panel getPanel1() {
if (panel1 == null) {
panel1 = new Panel();
panel1.setLayout(new GridBagLayout());
while(frame.isVisible()){
panel1.addMouseListener(new java.awt.event.MouseAdapter() {
public void mouseClicked(java.awt.event.MouseEvent e) {
frame.setVisible(false);
}
});
int r = (int) (Math.random()*255);
int g = (int) (Math.random()*255);
int b = (int) (Math.random()*255);
Color c = new Color(r, g, b);
panel1.setBackground(c);
try {
Thread.sleep(4000);
} catch (InterruptedException e1) {
e1.printStackTrace();
}
panel1.addMouseListener(new java.awt.event.MouseAdapter() {
public void mouseClicked(java.awt.event.MouseEvent e) {
/*panel1.setVisible(false);
frame.setVisible(false);*/
System.exit(0);
}
});
}
}
return panel1;
}
instead of exiting the loop of terminating the program or event changing the background it just displays the panel and does nothing else and i have to force it to quit. what should i do?
You're effectively blocking the UI thread by calling sleep in a loop. In that loop you're also adding two listeners on every iteration too, which is quite bizarre.
Don't block the UI thread. Let the GUI framework take care of delivering events etc. Basically you need to take an event-based approach to UI, rather than the approach you currently are taking, which will never let any events get despatched (as you're never returning control to the caller).
Create the panel, add the appropriate event listener, and then just return it to the caller. If you want to change the background colour every 4 seconds, you should do that via a timer so that it's not blocking the UI thread waiting for the 4 seconds to elapse.