I’ve created a simple vaadin application with a table on a page that is dynamically updated using the ICEpush addon from a thread I create in the attach() method of the panel. Each time it updates the page, it logs a message.
If I use ?restartApplication or restart my browser to get a fresh session then I start to see double the amount of log messages. The thread attached to the orphaned session continues to updated the table even though no client is connected.
Is there a way to harvest these orphan sessions? Is there a way to detect if the client is no longer connected and kill the thread I have created and Application instance?
I am not familiar with ICEpush addon, but You can implement manualy
HTTP session listener , attach it to Your application and stops the thread using appropriate way for ICEpush by implementing sessionDestroyed method.
ICEPush icepush = new ICEPush();
Table myTable = new Table()
publc void init() {
mainWindow.add(icepush)
mainWindow.add( myTable );
new BackgroundThread().start();
}
public class BackgroundThread extends Thread {
@Override
public void run() {
log.info("Started background thread to update table");
while (true) {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
}
updateTable(myTable)
}
}
}
}
I need the background thread to stop when the user has closed their browser/session has expired.
Can Http session listener help with this? if so - can you show me an example?
Or is there some way to do while (!getApplication.isExpired() ?
3 things that comes to my mind are the corrections to Your code:
Instead of extending Thread, try to implement Runnable interface like this:
public class BackgroundThread implements Runnable {
public void run() {
...
}
}
And start the thread like this:
new Thread( new BackgroundThread() ).start();
According to
Thread’s Java API You shouldn’t directly call stop() and - what is connected to this - using endless loop like “while( true )”. Instead of this, there should be some e.g. boolean field which works as “switch” which says to running thread it should stop ASAP. This switch should be checked once a time e,g,:
public class BackgroundThread implements Runnable {
boolean switch = true;
public void run() {
while( switch ) {
...
}
}
public void stopWorking() {
this.switch = false;
}
}
And when You want this thread to stop working - You just invoke method “stopWorking()” on instance of this thread.
From the code snippet I see that You want to update table from another thread so user will have table updated periodically. I guess it will not work as You expect because of Vaadin nature as a framework. UI (in You case - table) will be refreshed when User make some interaction to the server (e.g. click something). This is harder to achieve. Please read
this thread and read about
Refresher addon .
About implementing session listener I have to go to home and I’ll give You detailed info.
Application’s init() method implementation could be like this:
public class MyApp extends Application {
BackgroundThread thread;
publc void init() {
mainWindow.add(icepush)
mainWindow.add( myTable );
this.thread = new BackgroundThread();
new Thread( this.thread ).start();
}
public BackgroundThread getThread() {
return this.thread;
}
}
Session listener implementation could be like this (draft):
public class ThreadCleanerListener implements HttpSessionListener {
public void sessionCreated( HttpSessionEvent sessionEvent ) {
...
}
public void sessionDestroyed( HttpSessionEvent sessionEvent ) {
final WebApplicationContext waContext = WebApplicationContext.getApplicationContext( sessionEvent.getSession() );
final Iterator< Application > appIt = waContext.getApplications().iterator();
if ( appIt.hasNext() ) {
final Application app = appIt.next();
app.getThread().stopWorking();
} else {
...no application exists for this session.
}
}
}
Additionaly in BackgroundThread run method there could be passed instance of application which created this thread and in thread could be checking if application is running:
while( switch && this.app.isRunning() )
Session can be destroyed in 1 of 2 ways (generally):
You directly invalidate session by calling
invalidate() on HttpSession object.
In this case, session could be manualy invalidated when user logs out from the application - it depends on Your application use case/business logic.
session is timed out (then, container invalidates session). This happens when user closes the browser window without logging out. Timeout depends on Your application - is it 30 minutes (regular application) or 10 minutes (banking system).
Application is bind to session in Vaadin. isRunning can happen, when You somehow have reference to application instance, but this application is not bounded to any running session or application was already closed (somehow, e.g. by calling manually
close() method ).
Quick note: you want to declare that boolean field volatile or else there’s no guarantee that the running thread will see a change in its value. That’s the kind of error that won’t show up until months after your code is in production.