I’m using vaadin 7.0.5 and I’m having trouble in closing a window from a different thread.
The window simply doesn’t get closed. Never. It remains in the screen even if window.close() is called.
Basically, the window shows a ProgressIndicator and it is started when a long running task is required.
The close method is called but the dialog doesn’t get closed.
final ProgressIndicator pi = new ProgressIndicator();
pi.setIndeterminate(false);
pi.setEnabled(true);
pi.setValue(0f);
progressReport = new StuffProgressReport(pi);
wdw = new ProgressWindow("Waiting", pi);
wdw.show();
String[] calculations = getData();
Thread t = new Thread(new LongRunningTask(calculations));
t.start();
In the run method of LongRunningTask there is a simple finally statements that simply calls :
wdw.close();
ProgressWindow is defined as following:
public class ProgressWindow extends Window{
private static final long serialVersionUID = 161901606322111895L;
public ProgressWindow(String title, ProgressIndicator pi){
VerticalLayout root = new VerticalLayout();
root.setSizeFull();
root.addComponent(pi);
setContent(root);
setWidth(300, Unit.PIXELS);
setHeight(100, Unit.PIXELS);
}
public void show() {
Console.getCurrent().addWindow(this);
}
}
StuffProgressReport does the following. It simply refresh the ProgressIndicator about the job that is currently done.
class StuffProgressReport implements IProgressReport {
private ProgressIndicator pi;
private int maxStep = -1;
private int currentStep = 0;
private boolean isDone = false;
private boolean isAborted = false;
public StuffProgressReport(ProgressIndicator pi){
this.pi = pi;
}
@Override
public void begin(int totalWork) {
this.maxStep = totalWork;
this.currentStep = 0;
}
@Override
public void setTaskName(@NonNull String taskName) {
this.pi.setCaption(taskName);
}
@Override
public void worked(int installment) {
this.currentStep += installment;
// progress
if (currentStep == maxStep) {
pi.setEnabled(false);
pi.setValue(1f);
} else {
pi.setValue((float) currentStep / maxStep);
}
}
@Override
public void done() {
this.isDone = true;
pi.setValue(1f);
}
@Override
public boolean isAborted() {
return this.isAborted;
}
public boolean isDone() {
return isDone;
}
}
Does it disappear if you do something else in the application, like press a button or something? I don’t see any push or poll logic in there. A roundtrip between the server and browser goes always in the this direction: Browser → Server → Browser. If you do a change in another thread than the main one, vaadin won’t send the changes automatically in the sense of Server->Browser - client has to trigger it. If you do anything in the browser that causes a roundtrip to the server, then your other thread changes will also piggyback in that roundtrip. That’s why pressing a button or changing a value might “trigger” the close even if they have nothing to do with the thread.
There the options are to do poll or push. Poll says to the browser that it should do an empty roundtrip to the server every x milliseconds, to see if there is anything have been updated. Push tells the browser to open another channel between browser and server, which the server doesn’t respond to until there is something new on the server to push trough that channel.
Push without the use of add-ons is only supported in Vaadin 7.1.0.beta1 + but you could use the standard
ProgressIndicator Component which supports polling. Until you change to the newest version or start using one of the addons this would be the best (and only) option.
Looking at your code it looks like you call pi.setEnabled(false) in the worked method. Is it possible that you’re disabling the progress indicator, which is getting picked up in the next client poll, then later closing the window? Once the progress indicator has been disabled it will no longer poll for changes so the client will never pick up the window close state change (without using push).
You might want to leave the pi enabled but set indeterminate false and a value of 1 (or is it 100?). The pi will then continue to poll and pickup the window close state change. You could also look at using the Refresher plugin which is an invisible polling component/extension that you can leave enabled even if you disable the progress indicator.
I had a look through your code and i’m not quite sure if i understood the part with the StuffProgressReport class.
Basically you should hava a Worker thread which in the end does the changes to the UI (in your case closes the window) and then sets the value of the Progressindicator and disables the PI (like you do it in the voids worked and done). So you should make sure that this get done after the window.close method is called and not before it.
Please show the code for LongRunningTask. You
must properly lock the session when accessing the UI from a background thread, otherwise you do get race conditions and anything can happen. This is not optional. You must hold the lock only when actually doing something with the UI and release it as soon as possible, otherwise, as you say, request threads get starved waiting for the lock.