Right now – as I am writing this post – Vaadin is my favourite UI framework for Java web applications. While alot of frameworks seem to create just as much problems as they are trying to solve, Vaadin helps me in creating stylish reactive user interfaces. In this post I will show how to use some Java 8 concurreny features to update Vaadin elements asynchronously.

I created a small project to show the usage of CompletableFuture to perform a (long running) backend job asynchronously without blocking the UI. As I use maven as my build system I needed these dependencies for the project:


    
      com.vaadin
      vaadin-server
      ${vaadin.version}
    
    
      com.vaadin
      vaadin-client-compiled
      ${vaadin.version}
    
    
      com.vaadin
      vaadin-themes
      ${vaadin.version}
    
    
        com.vaadin
        vaadin-push
        ${vaadin.version}
    
    
      javax
      javaee-api
      ${jee.version}
      provided
    

This is a typical standard maven configuration for a Vaadin project, the vaadin-push library is essential for this project, as we want to use Vaadin’s push capabilities to update the user interfaces automatically.

Lets go on to the java side: first you need a standard Vaadin UI class with a simple label and a button. After clicking the button, a job will be started asynchonously. After the job is completed, the UI should be refreshed with a result (coming from the long running job).

@Theme("valo")
@Push
public class SampleUI extends UI {
  @WebServlet(value = "/*", asyncSupported = true)
  @VaadinServletConfiguration(productionMode = true, ui = SampleUI.class)
  public static class SampleUIServlet extends VaadinServlet {
  }
  
  @Override
  protected void init(VaadinRequest request) {
    final HorizontalLayout layout = new HorizontalLayout();
    layout.setSpacing(true);
    layout.setMargin(true);
    Label label = new Label("Check something ...");
    layout.addComponent(label);
    Button checkButton = new Button("Check");
    checkButton.setWidth("120px");
    layout.addComponent(checkButton);
    super.setContent(layout);
  }
}
a simple button and a label

To give our button a meaning, we should add a click listener (add this part in the init method after creating the button).

checkButton.addClickListener(event -> {
  checkButton.setIcon(null);
  CompletableFuture<Boolean> backendWorker = check();
  backendWorker.thenRunAsync(() -> {
    try {
      Boolean valid = backendWorker.get();
      updateUI(valid, checkButton);
    } catch (InterruptedException | ExecutionException e) {
      e.printStackTrace();
    }
  });
});

As you can see I created an CompletableFuture<Boolean> object (called backendWorker) that will perform the (long running) backend job. In the next line we call the thenRunAsync method of backendWorker (with a Runnable as argument) to update the user interface with the result of the backend process. With this result we update the user interface elements without blocking the UI.

The invocation of the backend process can look like this:

private CompletableFuture<Boolean> check() {
  CompletableFuture<Boolean> backendWorker = CompletableFuture.supplyAsync(() -> {
    try {
      Thread.sleep(3000);
      return new Random().nextBoolean();
    } catch (InterruptedException e) {
      return null;
    }
  });
  return backendWorker;
}

The check() method will just wait for 3 seconds and then return a (random) boolean value. With this result we can update the UI asynchronously :

private void updateUI(Boolean valid, Button button) {
  UI.getCurrent().access(() -> {
    if (valid == null) {
      return;
    }
    if (valid) {
      button.setIcon(FontAwesome.CHECK);
    } else {
      button.setIcon(FontAwesome.BAN);
    }
  });
}

To access a Vaadin UI from another thread, we need to use the access method of the UI class (otherwise you will get all kinds of strange effects).

the button is update with an Icon (coming from the results of the backend process)

After 3 seconds your UI will be updated automatically, because we marked the UI class with Vaadin’s @Push annotation. With this approach we are able to start long running backend jobs without blocking the UI to archieve a kick-ass user experience.

By Meik Kaufmann

I am a certified oracle enterprise architect and like to share my knowledge and experience that I gain in the projects I am working on.

Leave a Reply

Your email address will not be published. Required fields are marked *