Blog

Collaboration Engine: How the demo app works

By  
Mikael Sukoinen
Mikael Sukoinen
·
On Dec 8, 2020 4:15:00 PM
·
In Product

IMAGE (1)

The Vaadin Collaboration Engine is a set of features that enables end users of your Vaadin application to collaborate with each other in real time within the application. It was built to help people work together when not sharing an office space. It’s included in all commercial Vaadin subscription tiers.

You can try a Collaboration Engine demo here.

What is included in Collaboration Engine?

Even though it is a new feature, Vaadin Collaboration Engine is is ready for production and currently offers:

  • A high-level API for specific use cases, like those in this post.
  • A low-level Topic APIs for custom collaboration features.
  • Collaboration Avatar Group component that populates an avatar group with all the people present in the view, component or application.
  • CollaborationBinder that allows everyone using a form to see and share the activities of other users in real time.

We’re adding features, such as a live discussion and notifications, to the full release. See the release roadmap for details.

Demo

The demo app allows people to see who else is working on the form and edit it together in real time. It implements the new Collaboration Engine features in the contact form built in our CRM tutorial app. You can build an app like it by following our comprehensive tutorial series.

Screenshot 2020-12-08 at 15.12.39

In this post, we explain the Collaboration Engine features through text and code examples. Watch this webinar recording for a live coding demo.

Are you interested in implementing Collaboration Engine for your Vaadin app? Head over to the product page for pricing and availability.

Implementing Collaboration Engine features

Let’s take a look at how the Collaboration Engine features were implemented in the demo.

Installing Collaboration Engine

Adding dependencies

To install Collaboration Engine, add the following dependency in the <dependencies> tag of your pom.xml. See the release notes for the latest version number (currently 2.0.0):


<dependency>

    <groupId>com.vaadin</groupId>

    <artifactId>collaboration-engine</artifactId>

    <version>2.0.0</version>

</dependency>

This downloads and installs the new Collaboration Engine components.

NOTE: Collaboration Engine will not work in production mode without a valid license! See pricing and request access here. All commercial Vaadin subscriptions include a free quota of users.

The current version is available as a POM dependency. It is suitable if you deploy your Vaadin application on a single server, without clustering. The collaboration happens within the JVM, which means that end users will only see other users within the same server instance as they are on. However, we’re planning to release a Docker image next that will allow you to run it on a separate server within your infrastructure.

Enabling server push

To enable server push, add the @Push annotation to your MainView.Java:


@CssImport("./styles/shared-styles.css")

@Push

public class MainLayout extends AppLayout {

This opens a web socket that waits for data. When received, it immediately displays the data on the end user’s screen. 

Showing who is editing the form

Showing users

Open ContactForm.Java to add the collaboration features. First, create a new CollaborationAvatarGroup for our avatars:


CollaborationAvatarGroup avatars;

An Avatar depicts each user in the app and an AvatarGroup consists of multiple avatars. CollaborationAvatarGroup binds an AvatarGroup to Collaboration Engine automatically, eliminating the need for boilerplate code to build the logic. 

Next, instantiate the new group. This requires two parameters:

  • UserInfo: A class that identifies who each user is (picture and name). This requires a unique user id to identify what data belongs to whom. We assign “user” as the user id for now.
  • "app": A string that identifies our topic id. A topic id is an identifier in Collaboration Engine for sessions in which users can collaborate. We’ll return to this in more detail in the next step.

public ContactForm(List<Company> companies) {

   addClassName("contact-form");




   UserInfo UserInfo = new UserInfo(userid: "user");

avatars = new CollaborationAvatarGroup(userInfo, “app”)

Finally, add the new avatars component to the layout:


add(avatars,

   firstName,

   lastName,

   email,

   status,

   company,

   createButtonsLayout()

);

If you build and run the app at this point, you will see an avatar above the form labelled “Anonymous User” (on mouseover).

Screenshot 2020-11-27 at 8.53.49

You can also set a name:


   UserInfo UserInfo = new UserInfo(userid: "user");

UserInfo.setName("Mikael Sukoinen");

Now it can share this name with other users.

NOTE: Collaboration Engine automatically abbreviates and uses initials if there is no user avatar (for example, Mikael Sukoinen = MS).

TIP: Please refer to the technical documentation to see how to load user names and images from the backend.

Specifying which row is edited

Now we come back to the topicId that we previously named “app”. You can compare topicId to a room in which everyone can hear and see one another. Currently, all users use the same “app” topic id, which means that they can all see each other, regardless of what part of the application they have open. What we want to do instead, is to use a distinct topic id for each row in the grid, so that everyone viewing a specific row is in a “separate room”.

We achieve this by providing an identifier that specifies the row. These identifiers are always strings, and you can choose how to format them - they should be unique and distinct from each other, so you know what they are for.

Start by changing the topic id from "app" to null to show that we don’t have a topic yet:


avatars = new CollaborationAvatarGroup(user, topicid: )

Next, extract the "contact/" topic as a string to be able to reuse it. Then use setTopic to set the topic to "contact/" for the Avatars:


public void setContact(Contact contact) {

   this.contact = contact;

   binder.readBean(contact);

          String topic = “contact/” + contact.getId();

       avatars.setTopic(topic);

       binder.setTopic(topic, () -> contact);

}

The topicid will be set to "contact/" when editing it with id 2 etc.

Finally, add one more check:


public void setContact(Contact contact) {

   this.contact = contact;

   binder.readBean(contact);

   if(contact != null){

       avatars.setTopic(“contact/” + contact/getId());

   } else {

       avatars.setTopic(null);

   }

}

This defines the topic. If the contact is anything other than null, the specific topic is used. If the contact is null, it is removed.

Now you can see who is actively editing a row in the form. You can test this by opening the demo in two browser windows. Note how the two users appear and disappear when selecting and deselecting a row.

Screenshot 2020-11-27 at 8.52.06

Enabling collaborative editing 

Adding CollaborationBinder

The next step is to enable collaboration between users when editing the form.

We used Binder to bind the contact entity to the form. To be able to achieve collaboration on that entity, Vaadin created an extended version of Binder called CollaborationBinder.

First, replace Binder with CollaborationBinder and add Contact as the bean validation type:


CollaborationAvatarGroup avatars;

CollaborationBinder<Contact> binder;

private Contact contact;

Binder needs certain information for initialization. Initialize it under avatars with the Contact class and user topicid:


avatars = new CollaborationAvatarGroup(userInfo, topicid: null;)

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

Next, scroll to where the readBean method is used to populate the fields. As you will notice, it’s crossed out. The readBean method is deprecated by the Binder. We provide a new method binder.setTopic that takes a topicid and the initial object that you want to edit.

Add the Binder method and set the string topic for it:


public void setContact(Contact contact) {

   this.contact = contact;

   binder.readBean(contact);

   if(contact != null){

       String topic = “contact/” + contact.getId();

       binder.setTopic(topic);

       avatars.setTopic(topic);

   } else {

       avatars.setTopic(null);

   }

}

Next, add the supplier of the initial object: 


public void setContact(Contact contact) {

   this.contact = contact;

   binder.readBean(contact);

   if(contact != null){

       String topic = “contact/” + contact.getId();

       binder.setTopic(topic, () -> contact);

       avatars.setTopic(topic);

   } else {

       avatars.setTopic(null);

   }

}

What this means is that if no one edits this item in the CollaborationBinder, it  uses data from the Contact bean. But if someone has already edited the object, then we use the data in Collaboration Engine. We don’t want to overwrite with the data from the database, but rather to continue from where the other person left off.

And finally, comment out the old readBean method:


public void setContact(Contact contact) {

   this.contact = contact;

   //binder.readBean(contact);

   if(contact != null){

       String topic = “contact/” + contact.getId();

       binder.setTopic(topic, () -> contact);

       avatars.setTopic(topic);

   } else {

       avatars.setTopic(null);

   }

}

Now, the field that the user is working on becomes highlighted and shows the name of the user typing in it when you hover over it. Other users can now see who is working, which field they are working on, and the changes they are making. If the user has selected the field, but is currently in a different browser window, the highlight is removed to indicate that the user is not actively editing it.

NOTE: If two or more people try to edit the same field simultaneously, the data of the last user to blur the input field will be stored.

Are you ready to get started with Collaboration Engine? Head over to vaadin.com/collaboration to request access!

Mikael Sukoinen
Mikael Sukoinen
Mikael has a passion for writing text, code and music. He’s currently utilising his skills to explain difficult concepts in plain language at Vaadin Ltd.
Other posts by Mikael Sukoinen