When I call refreshAll() on the dataprovider in an clickevent handler on a button to update a listbox I get the above exception. The call is made within an ui.access() like this but it doesn’t help:
okButton = new Button("OK", clickEvent -> {
if (commitItemEdit()) {
ui.access(() -> {
dataProvider.refreshAll();
});
}
}
I’ve tried also without wrapping in ui.access() but no difference. Is there anything else that should be done to aquire that lock? My understanding was that since it is within the scope of a webcall then it shouldn’t been necessary to do that wrapping?
Some other information which could be relevant. I have an abstract base class where the button is created and which has the dataprovider instance. That class is extended by the page classes, which are stateful session beans. I doubt though that it should make any difference, and everything else is working fine. I can follow the stack trace to the right location both with and without the refreshAll() call within UI.access()
As mentioned on the call I have another page which is also a SFSB with a grid where update events are received via jms and refresh method is called with UI.access(), because that happens from a thread which is not part of a ui access. Updates on that page works fine.
What scope does the data provider have? It could be that you have ended up with a data provider that is shared between multiple sessions, which could explain why you get the exception.
The ui bean was stateful for historical reasons, it doesn’t have to be and it doesn’t solve the issue to remove @Stateful annotation. Dataprovider is in default scope, i.e. dependant, and there is only one session so issue can’t be that it’s shared over several session.
Looking with debugger and breakpoints I see that the thread calling the clickevent handler is named e.g. Task-16 which is also the same thread calling ListBox.rebuild(), but where the VaadinSession.hasLock() is called the thread name is ForkJoinPool.commonPool-worker7. That is why the exception is thrown, that thread does not have a lock. Look at these parts of the stacktrace (very long so I cut what happens before dataprovider.refreshAll())
This part is still the same thread as is calling clickevent handler:
Caused by: java.lang.IllegalStateException: java.lang.IllegalStateException: Cannot access state in VaadinSession or UI without lock
ing the session.
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
at java.util.concurrent.ForkJoinTask.getThrowableException(ForkJoinTask.java:593)
at java.util.concurrent.ForkJoinTask.reportException(ForkJoinTask.java:677)
at java.util.concurrent.ForkJoinTask.invoke(ForkJoinTask.java:735)
at java.util.stream.ForEachOps$ForEachOp.evaluateParallel(ForEachOps.java:160)
at java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateParallel(ForEachOps.java:174)
at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:233)
at java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:418)
at com.vaadin.flow.component.listbox.ListBox.rebuild(ListBox.java:178) <--- still thread Task-16
at com.vaadin.flow.component.listbox.ListBox.lambda$setDataProvider$78e8296$1(ListBox.java:94)
at com.vaadin.flow.data.provider.AbstractDataProvider.lambda$fireEvent$2(AbstractDataProvider.java:96)
at java.util.stream.ForEachOps$ForEachOp$OfRef.accept(ForEachOps.java:184)
at java.util.stream.ReferencePipeline$2$1.accept(ReferencePipeline.java:175)
at java.util.HashMap$EntrySpliterator.forEachRemaining(HashMap.java:1699)
at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:481)
at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:471)
at java.util.stream.ForEachOps$ForEachOp.evaluateSequential(ForEachOps.java:151)
at java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(ForEachOps.java:174)
at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
at java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:418)
at com.vaadin.flow.data.provider.AbstractDataProvider.fireEvent(AbstractDataProvider.java:94)
at com.vaadin.flow.data.provider.AbstractDataProvider.refreshAll(AbstractDataProvider.java:53)
This is from the ForkJoinPool.commonPool-worker7
Caused by: java.lang.IllegalStateException: Cannot access state in VaadinSession or UI without locking the session.
at com.vaadin.flow.server.VaadinSession.checkHasLock(VaadinSession.java:509)
at com.vaadin.flow.server.VaadinSession.checkHasLock(VaadinSession.java:523)
at com.vaadin.flow.internal.StateTree.checkHasLock(StateTree.java:390)
at com.vaadin.flow.internal.StateTree.markAsDirty(StateTree.java:258)
at com.vaadin.flow.internal.StateNode.markAsDirty(StateNode.java:510)
at com.vaadin.flow.internal.nodefeature.NodeList.addChange(NodeList.java:277)
at com.vaadin.flow.internal.nodefeature.NodeList.add(NodeList.java:238)
at com.vaadin.flow.internal.nodefeature.StateNodeNodeList.add(StateNodeNodeList.java:52)
at com.vaadin.flow.internal.nodefeature.ElementChildrenList.add(ElementChildrenList.java:42)
at com.vaadin.flow.dom.impl.AbstractNodeStateProvider.insertChild(AbstractNodeStateProvider.java:102)
at com.vaadin.flow.dom.Node.insertChild(Node.java:250)
at com.vaadin.flow.dom.Node.appendChild(Node.java:141)
at com.vaadin.flow.component.HasComponents.add(HasComponents.java:53)
at com.vaadin.flow.component.listbox.ListBox.lambda$rebuild$2(ListBox.java:178) <---- This is where the worker is fetched?
at java.util.stream.ForEachOps$ForEachOp$OfRef.accept(ForEachOps.java:184)
at java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:193)
at java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1382)
at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:481)
at java.util.stream.ForEachOps$ForEachTask.compute(ForEachOps.java:291)
at java.util.concurrent.CountedCompleter.exec(CountedCompleter.java:731)
at java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:289)
at java.util.concurrent.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1056)
at java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1692)
at java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:157)
With Vaadin 13.0.7 same Error here, but different Situation. We’ve one Session in a Browser, showing the Status of some Data in a Grid. There a several other Sessions changeing Data (moving pallets in logistics) on move they send a Message via ActiveMQ and the Grid should Update Data.
We extend AbstractBackEndDataProvider and return a parallelStream, also tested with stream, but same Error:
java.lang.IllegalStateException: Cannot access state in VaadinSession or UI without locking the session.
at com.vaadin.flow.server.VaadinSession.checkHasLock(VaadinSession.java:523)
at com.vaadin.flow.server.VaadinSession.checkHasLock(VaadinSession.java:537)
at com.vaadin.flow.internal.StateTree.checkHasLock(StateTree.java:390)
at com.vaadin.flow.internal.StateTree.beforeClientResponse(StateTree.java:321)
at com.vaadin.flow.data.provider.DataCommunicator.lambda$requestFlush$2f364bb9$2(DataCommunicator.java:425)
at com.vaadin.flow.internal.StateNode.runWhenAttached(StateNode.java:807)
at com.vaadin.flow.data.provider.DataCommunicator.requestFlush(DataCommunicator.java:424)
at com.vaadin.flow.data.provider.DataCommunicator.reset(DataCommunicator.java:176)
at com.vaadin.flow.data.provider.DataCommunicator.lambda$handleAttach$425c8a01$1(DataCommunicator.java:398)
at com.vaadin.flow.data.provider.AbstractDataProvider.lambda$fireEvent$2(AbstractDataProvider.java:96)
at java.util.stream.ForEachOps$ForEachOp$OfRef.accept(ForEachOps.java:184)
at java.util.stream.ReferencePipeline$2$1.accept(ReferencePipeline.java:175)
at java.util.HashMap$EntrySpliterator.forEachRemaining(HashMap.java:1699)
at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:482)
at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:472)
at java.util.stream.ForEachOps$ForEachOp.evaluateSequential(ForEachOps.java:151)
at java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(ForEachOps.java:174)
at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
at java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:418)
at com.vaadin.flow.data.provider.AbstractDataProvider.fireEvent(AbstractDataProvider.java:94)
at com.vaadin.flow.data.provider.AbstractDataProvider.refreshAll(AbstractDataProvider.java:53)
at de.pelzgroup.ui.dataproviders.AbstractPelzDataProvider.refreshAll(AbstractPelzDataProvider.java:129)
at de.pelzgroup.albatros.desktop.logistik.lager.Verladekontrolle.onMessage(Verladekontrolle.java:597)
You need to call refreshItem from within the thread that handles the current HTTP request (it automatically has the needed lock) or use UI.access or VaadinSession.access if you are running inside a background thread.
vkdp is an Instance of AbstractBackEndDataProvider
The Exception has gone, but the Grid updates not with a Push, only if the user selects a Item or do something else witch causes an interaction with Backend.
Root cause in my case was that the dataprovider returned a parallel stream, when returning a normal stream and executing the update within an ui.access() it worked as it should.
The access() method should handle pushing automatically unless it has been explicitly disabled (i.e. there should not be a need to manually call the push() method).