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
   }
  
}

[code]
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("");
    }
}

}
[/code]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();
            }
        }
                );
    }


}