Problem with ProgressIndicator and Application.close()

Hi!

I have a problem with a ProgressIndicator. If I close my application with Application.close() while a ProgressIndicator is active I get a SessionExpiredException with MSIE and Firefox while it seems to work on Chrome. Here is a minimal VAADIN 6.8.10 example, press the button and see the red “session expired” window pop up:

public class MyVaadinApplication extends Application {

@Override
public void init() {
	try {
		Thread.sleep(1000); // small delay to see the pop up before app gets restarted
	} catch (InterruptedException e) {
		e.printStackTrace();
	}

	Window window = new Window();
	setMainWindow(window);
	Button button = new Button(
			"Close this application while ProgressIndicator is running causing a SessionExpiredException",
			new Button.ClickListener() {
				@Override
				public void buttonClick(ClickEvent event) {
					close(); // might as well set the logout url here to go somewehere else but does not make a difference
				}
			});
	window.addComponent(button);
	ProgressIndicator progressIndicator = new ProgressIndicator();
	progressIndicator.setPollingInterval(50); // aggressive to make exception very likely to happen
	window.addComponent(progressIndicator); // remove this and the exception goes away on all browsers
}

}

I logged the VAADIN requests while pressing the button and here are my findings:


POST - /test/UIDL?windowName=1 … button click? (or progress indicator, a lot of these requests actually)
POST - /test/UIDL?windowName=1&onunloadburst=1 … app close?
GET - /test/
POST - /test/UIDL?windowName=1 … this seems to be the problematic request here caused by the progress indicator after the app got closed? this request never shows up here with Chrome, only MSIE and Firefox, if I remove the ProgressIndicator it is gone too
GET - /test/VAADIN/widgetsets/com.vaadin.terminal.gwt.DefaultWidgetSet/com.vaadin.terminal.gwt.DefaultWidgetSet.nocache.js?1366402830815 … page reload

Does a ProgressIndicator cancel its client side poller upon app close? Am I doing something wrong? Is it a bug? Is it a feature? Maybe someone can shed a bit of light on this?

Many thanks!

It is better to override close() of the Application to add code clean up code. I usually do removeAllComponents() and removeAllWindows() of the main window before invoking super.close(). This will give a clean screen to the user too. Also, you can free up other session specific resources if any.

Thank you for your answer. Unfortunately any changes during clean up (even removing components before Application.close()) will not get painted to the client side by VAADIN after an Application.close() was called.

AbstractCommunicationManager.paintAfterVariableChanges() just calls endApplication() which send a redirect to the client side so whatever cleanup/component-remove I do on the server side will not reach the client and the Poller of ProgressIndicator is a client side implementation.

Have alook at AbstractCommunicationManager.paintAfterVariableChanges():


private void paintAfterVariableChanges(Request request, Response response,
            Callback callback, boolean repaintAll, final PrintWriter outWriter,
            Window window, boolean analyzeLayouts) throws PaintException,
            IOException {

        if (repaintAll) {
            makeAllPaintablesDirty(window);
        }

        // Removes application if it has stopped during variable changes
        if (!application.isRunning()) {
=>          endApplication(request, response, application);				// here the client is instructed to redirect the browser
=>          return;                                                     // and here we exit the painting code ...
        }

        openJsonMessage(outWriter, response);
		...
=>      writeUidlResponce(callback, repaintAll, outWriter, window, analyzeLayouts); // ... while actual painting would happen here
		...
		closeJsonMessage(outWriter);
        outWriter.close();
}

private void endApplication(Request request, Response response,
		Application application) throws IOException {

	String logoutUrl = application.getLogoutURL();
	if (logoutUrl == null) {
		logoutUrl = application.getURL().toString();
	}
	// clients JS app is still running, send a special json file to tell
	// client that application has quit and where to point browser now
	// Set the response type
	final OutputStream out = response.getOutputStream();
	final PrintWriter outWriter = new PrintWriter(new BufferedWriter(
			new OutputStreamWriter(out, "UTF-8")));
	openJsonMessage(outWriter, response);
=>	outWriter.print("\"redirect\":{");                              // looks like this redirect is all the client gets
	outWriter.write("\"url\":\"" + logoutUrl + "\"}");
	closeJsonMessage(outWriter);
	outWriter.flush();
	outWriter.close();
	out.flush();
}

I have been digging deeper into the VAADIN client side code and it looks like the ProgressIndicator pollers do not get canceled at all. VAADIN relies on GWT Timer and GWT passes the timeout calls directly to window.setTimeout. It looks like Chrome upon receiving the redirect after Application.close() automatically cancels all window timeouts while
MSIE/Firefox do not cancel the active timeouts
. Which in turn means the VAADIN pollers will cause a SessionExpiredException on these browsers with a rather high probability. This probability increases with the time it takes to perform the redirect (e.g. slow connection, time consuming application init, high server load, …).

Can anyone confirm or refute this?