DataBinding and UI update

Hi!
In the following example code i display an model object in a form and update this model object from a different widget.
How can i get the form to automatically display the changes made to the model object?

Cheers and thanx in advance
Stefan

        final Person johnDo = new Person("John Doe");
        BeanItem<Person> p = new BeanItem<Person>(johnDo);
        Form personForm = new Form();
        personForm.setItemDataSource(p);
        
        Button changeName = new Button("Change Name");
        changeName.addListener(new Button.ClickListener() {
            public void buttonClick(ClickEvent event) {
                johnDo.setName("Oliver Cromwell");
            }
        });

Hi,

If you make the change trough the Item, it will be automatically reflected, but if you change the pojo directly, there is obviously no automatic way for the Item to know it has changed.

Best Regards,
Marc


Edit: that is: make the change to
p
not to
johnDo
.

Thank you Marc for answering my question.
The thing my app has to do goes deeper.
The database items my model objects are connected to are getting updated by several systems at the same time.
Not only from this Application or even from the web. The backend already can handle this concurrency and the POJO stay in sync(most of the time).
My question is if there is a specific VAADIN way of how to communicate such changes to the containers?
Maybe with some Addon?

Hey
Stefan

The Container expects to get a Property.ValueChangeEvent when the value of a property changes (and there are similar events for other changes, such as Item.PropertySetChangeEvent and so on).

Unfortunately there is afaik no good standardized way in java to listen for pojo changes - hopefully BeansBinding or something similar will change that in the future…

Best Regards,
Marc

Actually it is possible if you are using dao pattern or just can exactly detect object changes on server side.
You need to use some eventbus solution (e.g.

Blackboard
or

Mycila
or any other)

Next you add object change event broadcasting in dao.
Your vaadin application code should listen for this events (don’t forget to use weak listeners or remove listeners on app close).

But don’t try to change container on data change event, cause you will change only server side state and client will be still unchenged.

You can just remember what was changed.

From client side you need to listen for changes too. You can use Refresher or ICEPush addons to check server state.

In short, example scenario:

  1. Some object is changed and stored using dao
  2. Dao casts object change event
  3. Vaadin app recieves change event and sets e.g. containerChanged = true flag
  4. Refresher periodically calls some server side method, which checks if (containerChanged) and then updates container. (if container is updated during refresher call, client UI will be correctly updated)

I used this in my app. Not perfect but the only way I see to easilly synchronize clients.

This is not true (unless I misunderstood what you mean) - you can go ahead and change Containers or any UI components, as long as you remember to synchronize on the application instance. The UI changes will be reflected on the client the next time the client contacts the server (you can then use polling or push to make the client refresh automatically).

However, if you forget to synchronize on the application instance while updating the UI in a separate thread (outside of the request/response cycle), changes may or may not get painted - which is not nice.

Also, to be clear: yes, there are many ways to make the containers (etc) aware of changes to pojos, but nothing standard that automatically does that for you - you’ll have to decide on a method and implement that.

Best Regards,
Marc

Thank you, Marc, for this correction.
I was sure it is a bad thing to modify containers out of normal vaadin request/response cycle. Actually i was afraid of synchronization error, which vaadin shows when client state is not synchronized with server state.

To be sure: am I right that I can change everything on server side (in separate thread) and any next call from client will push all the changes to client side?
So I can modify server state without fear and use e.g. refresher to call empty method, which implicitly will reflect all server changes on client side.

Yes. But you
must
synchronize on the application instance whose components you are updating, otherwise changes may be lost and weirdness occur.

Best Regards,
Marc

Good ideas, thank you. I will take a look at the blackboard addon and mycila.

For the event bus.
A colleague has pointed me to this interesting “google tech talk” video.

http://www.youtube.com/watch?v=PDuhR18-EdM

From the fifteenth minute a GWT developer explaining what is behind an event bus and as such is used in GWT.

Cheers
Stefan

A brute force approach is as follows

  • Use setters explicitly for all your data
  • Make your setters fire events (“model events”)
  • Make your Vaadin UI components listen to these model events (or any other interested party, for that matter.) The listeners can be other Vaadin sessions. You can use the standard Java listeners, or Blackboard or EventRouter, whatever turns you on.
  • Upon reception of the event, update the Vaadin component (using the synchronized/repaint trick). Make sure the browsers are polling (using the Refresher component) or Push to the browser (using ICEPush)

Expanding a bit on the first two points. I use HBNContainer for my persistance layer, and I decided NOT to annotate my setters, but to use the properties directly. I changed HBNContainer so that when a Property is set, it fires the setter instead of trying to set the property directly itself using the Hibernate mechanisms. Works fine, I have 25 user sessions listening to changes that they can all inititiate (who can change what when is part of the model)

HI Marc

Just to follow up on this
Customer1 customer = new Customer1(“Bob”, “Smith”, new GregorianCalendar(1980, 5, 3)
.getTime());
customer.setCustomerType(“Silver”);
customer.setGender(“Male”);
// Wrap it in a BeanItem
BeanItem item = new BeanItem(customer);

    // Bind it to a component
    Form form = new Form();
    form.setItemDataSource(item);
    layout.addComponent(form);

// Try changing the pojo
customer.setCustomerType(“Gold”);
Somehow in the form I see that the Customer type getting reflected is Gold, I am expecting Silver as I have not changed the item. I believe if the item is changed, the change would have been reflected, but not here.

Regards
Kartik

I have same situation.
My way is:


personForm.setItemDataSource(p);

Button changeName = new Button(“Change Name”);
changeName.addListener(new Button.ClickListener() {
public void buttonClick(ClickEvent event) {
johnDo.setName(“Oliver Cromwell”);


personForm.setItemDataSource(p);//<<<<biding again

}
});