For file uploads we chose to use a BackgroundTask to display a progress bar. You can upload a file by pressing the “Upload” button on the “DataModelBrowse” screen:
By choosing a file and pressing “Upload” it triggers the method “uploadPlan()” which imports the Data from the file
“uploadPlan()” opens the Screen “ImportPreview” where the imported data can be validated by the user
By pressing “Ok” on the “ImportPreview” screen the imported data gets persisted to the database
Please note that I use “BackgroundWorkWindow.show()” to start both the first BackgroundTask in DataModelBrowse and the second BackgroundTask in “ImportPreview”:
@Subscribe("okBtn")
public OperationResult onOkBtnClick(Button.ClickEvent event) {
ValidationErrors validationErrors = screenValidation.validateUiComponents((ComponentContainer) this.getWindow().getFrame().getComponent("form"));
if (!validationErrors.isEmpty()) {
ScreenValidation screenValidation = getBeanLocator().get(ScreenValidation.class);
screenValidation.showValidationErrors(this, validationErrors);
return OperationResult.fail();
} else {
BackgroundWorkWindow.show(new BackgroundTask<Object, Object>(600, this
.getWindow().getFrameOwner()) {
@Override
public Object run(TaskLifeCycle<Object> taskLifeCycle) throws Exception {
// get entries from import and commit
return importDatabaseService.commit(options.getImportResult().getEntities());
}
}, messages.getMainMessage("uploadProgressTitle"), messages.getMainMessage("uploadProgressText"), false);
closeWithDiscard();
return OperationResult.success();
}}
This mechanism works perfectly fine when uploading the first file. However if you try to upload multiple files sequentially it wont work. Instead an IllegalConcurrentAccessException is thrown:
“UI Shared state was accessed from a background thread”
The documentation states that this Exception occours whenever one tries to read/change UI components from the background task. I can’t figure out why it happens in my code. Maybe the exception is related to the fact that I start a BackgroundTask within a BackgroundTask? Thanks in advance.
Hi,
Your run() methods look correct. They don’t access anything they shouldn’t.
Can you show full exception stack trace? It contains information useful for debugging.
Also I don’t understand, if you “upload multiple files sequentially” - how your logic is organized? Do you expect multiple dialogs to be opened simultaneously, or sequentially one by one?
I don’t expect several files to be uploaded simultaneously. With sequentially I mean that the files get uploaded one by one.
There will always be one file uploaded at the time with a single dialog opened.
Stacktrace:
14:18:22.237 ERROR c.h.c.gui.executors.BackgroundWorker - Exception occurred in background task
com.haulmont.cuba.gui.executors.IllegalConcurrentAccessException: UI Shared state was accessed from a background thread
at com.haulmont.cuba.web.App.lambda$static$695e4c50$1(App.java:92) ~[cuba-web-7.2.13.jar:7.2.13]
at com.vaadin.server.AbstractClientConnector.markAsDirty(AbstractClientConnector.java:162) ~[vaadin-server-8.9.2-19-cuba.jar:8.9.2-19-cuba]
at com.vaadin.v7.ui.Table.markAsDirty(Table.java:1859) ~[vaadin-compatibility-server-8.9.2-19-cuba.jar:8.9.2-19-cuba]
at com.vaadin.v7.ui.Table.refreshRenderedCells(Table.java:1768) ~[vaadin-compatibility-server-8.9.2-19-cuba.jar:8.9.2-19-cuba]
at com.haulmont.cuba.web.widgets.CubaGroupTable.refreshRenderedCells(CubaGroupTable.java:751) ~[cuba-web-widgets-7.2.13.jar:na]
at com.vaadin.v7.ui.Table.refreshRowCache(Table.java:2670) ~[vaadin-compatibility-server-8.9.2-19-cuba.jar:8.9.2-19-cuba]
at com.haulmont.cuba.web.widgets.CubaTable.refreshRowCache(CubaTable.java:1132) ~[cuba-web-widgets-7.2.13.jar:na]
at com.vaadin.v7.ui.Table.valueChange(Table.java:4247) ~[vaadin-compatibility-server-8.9.2-19-cuba.jar:8.9.2-19-cuba]
at com.haulmont.cuba.web.gui.components.table.TableDataContainer.datasourceValueChanged(TableDataContainer.java:294) ~[cuba-web-7.2.13.jar:7.2.13]
at com.haulmont.bali.events.EventHub.publish(EventHub.java:170) ~[cuba-global-7.2.13.jar:7.2.13]
at com.haulmont.cuba.gui.components.data.table.ContainerTableItems.containerItemPropertyChanged(ContainerTableItems.java:98) ~[cuba-gui-7.2.13.jar:7.2.13]
at com.haulmont.bali.events.EventHub.publish(EventHub.java:170) ~[cuba-global-7.2.13.jar:7.2.13]
at com.haulmont.cuba.gui.model.impl.InstanceContainerImpl.itemPropertyChanged(InstanceContainerImpl.java:178) ~[cuba-gui-7.2.13.jar:7.2.13]
at com.haulmont.chile.core.model.impl.AbstractInstance.propertyChanged(AbstractInstance.java:57) ~[cuba-global-7.2.13.jar:7.2.13]
at de.importing.ImportResult.lambda$getEntities$2(ImportResult.java:165) ~[importing.jar:na]
at java.util.ArrayList.forEach(ArrayList.java:1259) ~[na:1.8.0_282]
at de.importing.ImportResult.getEntities(ImportResult.java:164) ~[importing.jar:na]
at de.importing.ImportPreview$1.run(ImportPreview.java:124) ~[importing.jar:na]
at com.haulmont.cuba.gui.backgroundwork.LocalizedTaskWrapper.run(LocalizedTaskWrapper.java:57) ~[cuba-gui-7.2.13.jar:7.2.13]
at com.haulmont.cuba.web.gui.executors.impl.WebBackgroundWorker$WebTaskExecutor.call(WebBackgroundWorker.java:219) ~[cuba-web-7.2.13.jar:7.2.13]
at java.util.concurrent.FutureTask.run(FutureTask.java:266) ~[na:1.8.0_282]
at com.haulmont.cuba.web.gui.executors.impl.WebBackgroundWorker$WebTaskExecutor.lambda$startExecution$1(WebBackgroundWorker.java:390) ~[cuba-web-7.2.13.jar:7.2.13]
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) ~[na:1.8.0_282]
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) ~[na:1.8.0_282]
at java.lang.Thread.run(Thread.java:748) ~[na:1.8.0_282]
The error is here.
In the ImportResult.lambda$getEntities$2 you modify some entity which is displayed in the table. It triggers property changed listener and causes table repaint.
You shouldn’t modify entities that are bound to UI components inside of run() method.