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:
- 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
-
- Once called, it creates a new thread that does a time-consuming (a few seconds) operation on the database
- 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.