Search code examples
javamultithreadingvaadinvaadin7

Dynamically remove and add components in vaadin from a thread


I have a Vaadin 7 application that has a common layout and in which there is a button, that starts a thread, that does some computing.

There is a component that receives information from the computation and displays progress information etc.

Now, when I start the application and execute the computation thread, everything is fine and the view is build correctly.

When its done and I rerun it, by simply pressing the start button again, I do get

Exception in thread "Thread-56" java.lang.IllegalStateException: A connector should not be marked as dirty while a response is being written.
at com.vaadin.ui.ConnectorTracker.markDirty(ConnectorTracker.java:505)
at com.vaadin.server.AbstractClientConnector.markAsDirty(AbstractClientConnector.java:141)
at com.vaadin.ui.AbstractComponentContainer.removeComponent(AbstractComponentContainer.java:227)
at com.vaadin.ui.AbstractOrderedLayout.removeComponent(AbstractOrderedLayout.java:178)
at com.test.pipeline.view.ResultPanel.rebuildResultLayout(ResultPanel.java:46)
at com.test.pipeline.view.ResultUIProcessListener.startTests(ResultUIProcessListener.java:40)
at com.test.pipeline.RanorexClient$RanorexWorker$$Lambda$224/988244250.accept(Unknown Source)
at java.util.ArrayList.forEach(ArrayList.java:1249)
at com.test.pipeline.RanorexClient$RanorexWorker.inform(RanorexClient.java:99)
at com.test.pipeline.RanorexClient$RanorexWorker.run(RanorexClient.java:64)

The RanorexoClient$RanorexWorker is a Thread doing the computation. There are listeners registered to the worker to get informed.

So I have a chain form a Thread to change UI.

The rebuildResultLayout looks like this

void rebuildResultLayout() {
    mainLayout.removeComponent(resultLayout);
    resultLayout = new VerticalLayout();
    mainLayout.addComponent(resultLayout);
}

so remove a layout, creating it new and adding it again. This is to get rid of information from previous run - I also tried simply to resultLayout.removeAllComponents(), but this results in the same error.

I read somewhere to synchronise the call to the UI, so currently my inform method looks like this

private void inform(Consumer<TestProcessListener> action) {
    synchronized (UI.getCurrent()) {
        processListeners.forEach(action);
    }
}

What is wrong ? What must be done to avoid the exception ?


Solution

  • As described in https://vaadin.com/docs/-/part/framework/advanced/advanced-push.html it is required to wrap the ui modification inside a ui.access() call.

    See also @André Schild comment that it must be ensured that a valid UI reference exists