Important Notice - Forums is archived
To simplify things and help our users to be more productive, we have archived the current forum and focus our efforts on helping developers on Stack Overflow. You can post new questions on Stack Overflow or join our Discord channel.

Vaadin lets you build secure, UX-first PWAs entirely in Java.
Free ebook & tutorial.
BeanItemContainer, Grid and Multithreading
Hello,
I've decided to use Vaadin for an Monitoring Web App, and so far I'm very happy with that decission!
But I have one kinda bigger problem:
We have a Class MachineManager in a singelton architecture. This class starts a thread, which permanently updates the public BeanItemContainer this class ownes. This container is used as a Datasource for an Grid in an UI-thread.
Naturally, as we are using Java, the Container is copied, and changes in the Managers Container don't arrive in the UI (only when refreshing). Do I have to accept my fate, and copy the container every few seconds to the UI or is there anything better in such situations?
Simplified:
public class MachineManager{
public BeanItemContainer<Machine> machineContainer = new BeanItemContainer<>(Machine.class);
// Singelton Architecture!
private static ManageMachines instance;
// Refresh machineContainer every 10 seconds
Thread autoRefresh = new Thread(new Runnable() {
public void run() {
while(true){
refreshAllMachines();
Thread.sleep(1000);
}
}
});
private ManageMachines () {
// start autorefreshing thread
autoRefresh.start();
}
.....
private void refreshAllMachines(){...
// Changes the content of machineContainer
}
}
public class ManageMachinesView extends HorizontalLayout implements View {
private Grid machineTable;
public ManageMachinesView(){
// Create Grid with all Machines
machineTable = new Grid(ManageMachines.getInstance().machineContainer);
machineTable.setEditorEnabled(false);
machineTable.setSelectionMode(SelectionMode.NONE);
// Parent Panel
Panel wrapperPanel = new Panel("Maschinen verwalten");
wrapperPanel.setContent(machineTable);
wrapperPanel.setSizeUndefined();
addComponent(wrapperPanel);
setComponentAlignment(wrapperPanel, Alignment.MIDDLE_CENTER);
setSizeFull();
}
@Override
public void enter(ViewChangeEvent event) {
if(VaadinSession.getCurrent().getAttribute("user") == null){
UI.getCurrent().getNavigator().navigateTo("");
}
}
}
I've already tried to edit the propertys by id (so the grid is notified), that didnt work.
I've also tried to get my own Container with Listeneners, but I failed with that.
So thanks in advance for any help or ideas.
Joel
Have you checked how to enable Vaadin Push and how to use UI.access() method in your threads? There is a chapter in Book of Vaadin covering the topic. I think this should solve most of your issues.
https://vaadin.com/book/-/page/advanced.push.html
Vaadin Push is enabled, but it doesn't seem to work. First I used the @push anotation, later i tried it with writing it in the web.xml.
The DataSource of the Grid is up to date.
I now implemented the Broadcaster like the example in the books. On every update there is a broadcast.
This is the receiveBroadcast method.
@Override
public void receiveBroadcast(String message) {
indexUI.getCurrent().access(new Runnable() {
@Override
public void run() {
machineTable = new Grid(ManageMachines.getInstance().machineContainer);
}
});
}
This method is executed, an system.out... works. So there seems to be an issue with "Push". It doesn't even work to add an label or something.
This is a kind of strange, because the automatic push works just fine in an other view.
"You can use server push in two modes: automatic and manual. The automatic mode pushes changes to the browser automatically after access() finishes." from https://vaadin.com/book/-/page/advanced.push.html#advanced.push.running
Tho only other thing I have is this Warning, when first visiting the UI:
Jan 12, 2016 1:11:07 PM com.vaadin.server.communication.PushAtmosphereHandler onRequest
WARNUNG: AtmosphereHandler.onRequest called before PushHandler has been set. This should really not happen
But I don't know what this should mean. Google didn't help me either.
How do you call receiveBroadcast? I would bet that "indexUI.getCurrent()" returns the wrong UI instance in at least some cases (the UI instance of the caller thread). It's much safer to store the UI instance in the listener and use that
I think you are right!
The thread, that calls the broadcaster, doesn't even belong to an UI-Object.
How can I make shure to get the "right" UI?
My following code only works after refreshing.
public class ManageMachinesView extends HorizontalLayout implements View, Broadcaster.BroadcastListener {
public final UI listenersUI;
private Grid machineTable;
public ManageMachinesView(){
listenersUI = indexUI.getCurrent();
....
}
@Override
public void detach(){
System.out.println("Detach View");
Broadcaster.unregister(this);
super.detach();
}
@Override
public void receiveBroadcast(String message) {
listenersUI.access(new Runnable() {
@Override
public void run() {
machineTable = new Grid(ManageMachines.getInstance().machineContainer);
addComponent(new Label("Test"));
listenersUI.push();
}
}
);
}
}