Blog

How to enable real-time collaboration in your Vaadin app in 4 steps

By  
Marcus Hellberg
Marcus Hellberg
·
On Jun 10, 2021 11:12:23 AM
·
In Product

Most web applications are collaborative. You have multiple users, all working with the same underlying data in the database. However, in most existing business applications, this collaboration doesn't happen in real time, which can lead to mistakes, inconsistent data, and lost working time.

 

Why real-time collaboration is important

Consider a shopping list shared by two family members, Bob and Alice. 

Bob logs in and adds some items to the list:

Bob

1 Carton of milk

6 Bananas

12 Eggs

 

While Bob is still logged in, Alice logs in and makes some modifications to the list: 

Bob

Alice

1 Carton of milk

6 Bananas

12 Eggs

1 Carton of milk

6 Bananas

18 Eggs

6 Apples

1 Bag of flour

 

Bob doesn't see Alice's changes. He decides they don't need that many eggs, so he modifies the list:

Bob

Alice

1 Milk

6 Bananas

6 Eggs

1 Milk

6 Bananas

18 Eggs

6 Apples

1 Bag of flour

 

At this point, Bob gets a save conflict as Alice has already changed the same item. 

We now have a situation where Bob, Alice, and the database all contain different data – none of it correct.

Now contrast that with this collaborative version of the same app. Bob can see that Alice is looking at the shopping list. Alice can let Bob know that she wants to add some things to the list. Bob can see Alice's changes in real time. 

This time, there's no confusion, no error, and we only have one version of the shopping list that is correct.

Collaborative shopping list

This is what Vaadin Collaboration Engine does. It allows you to add real-time collaboration to your Vaadin app in just a few lines of code. The four steps below walk through the changes needed.

1. Enable Collaboration Engine

Vaadin 20 includes Collaboration Engine by default. If you are using Vaadin 14, you need to add the dependency to your pom.xml file:

<dependency>
<groupId>com.vaadin</groupId>
<artifactId>collaboration-engine</artifactId>
<version>3.1.0</version>
</dependency>

 

Next, add a @Push annotation on your Application.java class to enable a two-way web socket connection.

@Push
@SpringBootApplication
public class Application extends SpringBootServletInitializer implements AppShellConfigurator {

public static void main(String[] args) {
LaunchUtil.launchBrowserInDevelopmentMode(SpringApplication.run(Application.class, args));
}

}

 

You can now start to use Collaboration Engine.

2. Identify and display online users

Collaboration Engine uses a UserInfo object to identify users. Create a UserInfo object based on your authenticated user:

var userInfo = new UserInfo(user.getId(), user.getName(), user.getAvatar());

 

Only the ID is required, but defining the name and avatar will improve the collaboration experience.

You can now display online users in a CollaborationAvatarGroup by passing in the UserInfo object and a topic:

var avatars = new CollaborationAvatarGroup(userInfo, 
"shopping-list");

 

image3-2

The topic is a string that defines the context or scope of collaboration. For example, the topic could be:

  • "app" if you are showing all online users in the entire app
  • "shopping-list-chat" if you have a chat on a specific view
  • "item/12" for collaborative editing of a specific item

 

3. Add context-aware discussions

You can add a context-specific discussion with the CollaborationMessageList and CollaborationMessageInput components:

var messageList = new CollaborationMessageList(userInfo, "shopping-list-chat");
var messageInput = new CollaborationMessageInput(messageList);
var chatLayout = new VerticalLayout(
messageList,
messageInput
);


Remember to define an appropriate topic to scope the chat to the correct context.

image1-2

4. Enable collaborative form editing

You can turn an existing form that uses Binder into a collaborative form by using CollaborationBinder instead:

CollaborationBinder<ShoppingListItem> binder = new CollaborationBinder<>(
ShoppingListItem.class, userInfo);

CollaborationBinder does not use the readBean/setBean API that Binder uses. Instead, you should define the topic and a method that provides the initial value. This way, binder will use the shared value, if one exists, and use the provider method to initialize itself, if needed.

public void setItem(long id) {
binder.setTopic("item/" + id, () -> service.findById(id));
}

 

image2-1

You can find the source code for the Shopping List app on GitHub.

Next steps

In addition to these built-in components, the Collaboration Engine Topic API supports creating shared data structures that you can use to synchronize any other data you need between all online clients.

Read the Collaboration Engine Docs for more help on how to enable collaboration in your Flow app.

Don't have a flow app yet? No problem! You can configure and download a starter project with Collaboration Engine installed from start.vaadin.com.

Marcus Hellberg
Marcus Hellberg
Marcus is the VP of Developer Relations at Vaadin. His daily work includes everything from writing blogs and tech demos to attending events and giving presentations on all things Vaadin and web-related. You can reach out to him on Twitter @marcushellberg.
Other posts by Marcus Hellberg