Blog

Anticipating 7.1.0, Server push

By  
Henrik Paul
·
On May 30, 2013 9:50:00 AM
·

Asynchronous updates of the UI have always been very high on the wishlists of many Vaadin developers. Even I stumbled upon the need for asynchronous updates during my junior years, without even realizing it. I thought Vaadin was broken somehow. I mean, if my button’s click listener can change the contents of the screen, why can’t my asynchronous data-gathering thread do that too?

Due to the architecture of both Vaadin and HTTP (mostly HTTP, though), you can’t do that out of the box. Normally, the user interacts with the application, a request is sent to the server, and finally the UI changes are sent back in a response to the ongoing request. Thus, the communication loop is closed and no data will move between the two anymore, until the next interaction.

Disregarding a few hacky add-ons, that’s how it works now, and has worked since the beginning of Vaadin. Vaadin 7.1.0 introduces server push - the ability to do asynchronous changes to what the user sees, without the requirement of user interaction.

Everything you see now is available in Vaadin 7.1.0 beta1, so feel free to try it out yourself.

Configuring your project and server

Here’s a little application that I wrote that does what I tried to do with the database a few years back: Fetch data from a slow database without compromising the responsiveness of the application.

We start by creating a new Ivy-managed Vaadin 7 application, with Vaadin 7.1.0 beta1 as the version (or a stable version of Vaadin 7.1, once it’s out). At the time of writing, we need to manually add the dependencies for push. This will be automated by the Eclipse plug-in for you by the time of release, however.

For Ivy, add this to your ivy.xml to get the push dependencies:

<dependency org="com.vaadin" name="vaadin-push" rev="&vaadin.version;" conf="default->default" />

Maven users can use this snippet:

<dependency>
   <groupId>com.vaadin</groupId>
   <artifactId>vaadin-push</artifactId>
   <version>${vaadin.version}</version>
</dependency>

To actually enable server push for my application, I add the annotation @com.vaadin.annotations.Push to my UI class. This is just to let Vaadin know to prepare for push requests. Also, if your project is set up as a Servlet 3.0, you need to add <async-supported>true</supported> to your web.xml for your application’s <servlet> configuration. Now we’re done with our prep work, and ready to actually make some pushing happen.

Code to push

For this blog post, I’ve written a simple application that fetches data from a slow database. To optimize the responsiveness of the UI, initially I’ll show a placeholder Label, which will eventually be replaced with the actual result asynchronously. If we weren’t using push here, rendering the UI would be put on hold for as long as the database is working, and that makes for a terrible user experience.

Main UI

protected void init(final VaadinRequest request) {
    VerticalLayout layout = new VerticalLayout();
    setContent(layout);

    // adding a placeholder label, changed afterwards.
    dbLabel = new Label("Fetching data from database...");
    layout.addComponent(dbLabel);

    DatabaseWorker dbWorker = new DatabaseWorker();
    dbWorker.fetchAndUpdateDataWith(this);
}

Here are the application visuals in all their glory – a simple label dbLabel that will initially display a placeholder text, and the text is later on updated with the actual data. For application simplicity’s sake, dbLabel is an instance field, so that it’s easier to change its value later on.

DatabaseWorker is a class that I wrote for this example. Its exact implementation is uninteresting, so I won’t put its code here. But what it does is basically as follows:

  1. It has a method fetchAndUpdateDataWith(LabelUpdater labelUpdater)
    • LabelUpdater is a simple interface I created that my UI implements. It has only one method, updateLabel(String string), which we’ll come back to in a while
  2. Once called, it creates a new thread that does a time-consuming (a few seconds) operation on the database
  3. Once the database returns its result, the created thread uses the LabelUpdater.updateLabel callback method with the database result.

The last step brings us back to our UI class, since the callback method is implemented by my UI. Here’s where the push starts to happen!

Push logic

public void updateLabel(final String string) {
    access(new Runnable() {
        @Override
        public void run() {
            dbLabel.setValue(string);
        }
    });
}

That’s pretty much it. Done. Push will happen.

Oh right, the “what’s going on here?” The key here is the access(Runnable runnable) method. It’s a method from com.vaadin.ui.UI, and it makes sure that concurrency is handled correctly and that the changes are pushed to the browser if automatic push is enabled (which I have, due to the @Push annotation). If there are multiple UI instances involved, make sure to call the access method for the correct UI instance – this is something to note especially if the method calling access happens to be a static method, as you can’t blindly trust that methods like UI.getCurrent() would return the correct instance.

The access method takes an instance of Runnable, which I have here made as an anonymous inner class. The Runnable.run method body will contain the logic to update the UI on the browser. You should do all business logic outside of this access call, and only do UI updates within the Runnable you pass to the access method. Calling the method locks the UI instance, and doing business logic within the access call will possibly slow down UI updates.

Epilogue

While this application by itself doesn’t make that much sense, it aims to demonstrate a real-world possibility of how server push can be useful in a larger context. Push is a great tool to improve the responsiveness of your applications when your back-end is slow, and introduces yet another point of possible optimization. Another typical use case for push is to show a constantly updating stream of server-side information.

Just note that push requires a direct communication between one client and one server. Load balancers might introduce some problems, since websockets are hard to transfer between servers in the middle of the execution.

Try it out yourself

You can check out and try the application yourself. If you add ?debug at the end of the URL, you’ll see the debug console and a run-down of the communication between the server and client. I’ve also made the Eclipse project available.

Henrik Paul
Henrik Paul works as a Scrum Master at Vaadin's product development. He has been working at Vaadin since 2008 with basically anything and everything, except in sales or administration. He's one of those annoying guys who is never satisfied with the status quo, and questions established practices constantly.
Other posts by Henrik Paul