This tutorial shows how to build a view with a checkbox where the user can choose whether they are in a Friday mood.
Create a Simple View
First, create the view with a checkbox but not yet any collaborative functionality.
Source code
TopicView.java
package com.vaadin.demo.ce;
import com.vaadin.collaborationengine.CollaborationEngine;
import com.vaadin.collaborationengine.CollaborationMap;
import com.vaadin.collaborationengine.UserInfo;
import com.vaadin.flow.component.UI;
import com.vaadin.flow.component.checkbox.Checkbox;
import com.vaadin.flow.component.orderedlayout.VerticalLayout;
import com.vaadin.flow.router.Route;
import com.vaadin.flow.shared.Registration;
@Route(value = "ce/topic", layout = MainView.class)
public class TopicView extends VerticalLayout {
private final Checkbox checkbox;
public TopicView() {
checkbox = new Checkbox("Is it Friday?");
add(checkbox);
// NOTE: In a real application, use the user id of the logged in user
// instead
String userId = System.identityHashCode(UI.getCurrent()) + "";
UserInfo localUser = new UserInfo(userId, "User " + userId);
CollaborationEngine.getInstance().openTopicConnection(this, "tutorial",
localUser, topic -> {
CollaborationMap fieldValues = topic
.getNamedMap("fieldValues");
Registration registration = checkbox
.addValueChangeListener(valueChangeEvent -> {
fieldValues.put("isFriday",
valueChangeEvent.getValue());
});
fieldValues.subscribe(event -> {
if ("isFriday".equals(event.getKey())) {
checkbox.setValue(Boolean.TRUE
.equals(event.getValue(Boolean.class)));
}
});
return registration;
});
}
}
Define Topic Connection
Sharing data between multiple users happens through a TopicConnection instance.
By default, the connection is deactivated until its related component is attached to the UI.
Open a connection to the tutorial topic and define the activation callback which is triggered when the current TopicView component (this) is attached.
The user who is related to the topic connection must be defined.
Source code
TopicView.java
package com.vaadin.demo.ce;
import com.vaadin.collaborationengine.CollaborationEngine;
import com.vaadin.collaborationengine.CollaborationMap;
import com.vaadin.collaborationengine.UserInfo;
import com.vaadin.flow.component.UI;
import com.vaadin.flow.component.checkbox.Checkbox;
import com.vaadin.flow.component.orderedlayout.VerticalLayout;
import com.vaadin.flow.router.Route;
import com.vaadin.flow.shared.Registration;
@Route(value = "ce/topic", layout = MainView.class)
public class TopicView extends VerticalLayout {
private final Checkbox checkbox;
public TopicView() {
checkbox = new Checkbox("Is it Friday?");
add(checkbox);
// NOTE: In a real application, use the user id of the logged in user
// instead
String userId = System.identityHashCode(UI.getCurrent()) + "";
UserInfo localUser = new UserInfo(userId, "User " + userId);
CollaborationEngine.getInstance().openTopicConnection(this, "tutorial",
localUser, topic -> {
CollaborationMap fieldValues = topic
.getNamedMap("fieldValues");
Registration registration = checkbox
.addValueChangeListener(valueChangeEvent -> {
fieldValues.put("isFriday",
valueChangeEvent.getValue());
});
fieldValues.subscribe(event -> {
if ("isFriday".equals(event.getKey())) {
checkbox.setValue(Boolean.TRUE
.equals(event.getValue(Boolean.class)));
}
});
return registration;
});
}
}
The activation callback should return a registration, which Collaboration Engine runs when the connection is deactivated.
Since the example does not (yet) register any own listeners that need cleanup, it can just return null.
Define a category in the Topic
The topic stores collaborative data in named maps.
In the activation callback, get a map by its name:
Source code
TopicView.java
package com.vaadin.demo.ce;
import com.vaadin.collaborationengine.CollaborationEngine;
import com.vaadin.collaborationengine.CollaborationMap;
import com.vaadin.collaborationengine.UserInfo;
import com.vaadin.flow.component.UI;
import com.vaadin.flow.component.checkbox.Checkbox;
import com.vaadin.flow.component.orderedlayout.VerticalLayout;
import com.vaadin.flow.router.Route;
import com.vaadin.flow.shared.Registration;
@Route(value = "ce/topic", layout = MainView.class)
public class TopicView extends VerticalLayout {
private final Checkbox checkbox;
public TopicView() {
checkbox = new Checkbox("Is it Friday?");
add(checkbox);
// NOTE: In a real application, use the user id of the logged in user
// instead
String userId = System.identityHashCode(UI.getCurrent()) + "";
UserInfo localUser = new UserInfo(userId, "User " + userId);
CollaborationEngine.getInstance().openTopicConnection(this, "tutorial",
localUser, topic -> {
CollaborationMap fieldValues = topic
.getNamedMap("fieldValues");
Registration registration = checkbox
.addValueChangeListener(valueChangeEvent -> {
fieldValues.put("isFriday",
valueChangeEvent.getValue());
});
fieldValues.subscribe(event -> {
if ("isFriday".equals(event.getKey())) {
checkbox.setValue(Boolean.TRUE
.equals(event.getValue(Boolean.class)));
}
});
return registration;
});
}
}
Pass Values to the Topic
The first actual step to making the application collaborative is to update the topic whenever the checkbox value changes.
isFriday is the key associated with the value of the checkbox.
Add a value change listener that updates the related topic map.
Source code
TopicView.java
package com.vaadin.demo.ce;
import com.vaadin.collaborationengine.CollaborationEngine;
import com.vaadin.collaborationengine.CollaborationMap;
import com.vaadin.collaborationengine.UserInfo;
import com.vaadin.flow.component.UI;
import com.vaadin.flow.component.checkbox.Checkbox;
import com.vaadin.flow.component.orderedlayout.VerticalLayout;
import com.vaadin.flow.router.Route;
import com.vaadin.flow.shared.Registration;
@Route(value = "ce/topic", layout = MainView.class)
public class TopicView extends VerticalLayout {
private final Checkbox checkbox;
public TopicView() {
checkbox = new Checkbox("Is it Friday?");
add(checkbox);
// NOTE: In a real application, use the user id of the logged in user
// instead
String userId = System.identityHashCode(UI.getCurrent()) + "";
UserInfo localUser = new UserInfo(userId, "User " + userId);
CollaborationEngine.getInstance().openTopicConnection(this, "tutorial",
localUser, topic -> {
CollaborationMap fieldValues = topic
.getNamedMap("fieldValues");
Registration registration = checkbox
.addValueChangeListener(valueChangeEvent -> {
fieldValues.put("isFriday",
valueChangeEvent.getValue());
});
fieldValues.subscribe(event -> {
if ("isFriday".equals(event.getKey())) {
checkbox.setValue(Boolean.TRUE
.equals(event.getValue(Boolean.class)));
}
});
return registration;
});
}
}
The topic’s structure now looks as follows:
Source code
Topic maps
|_ fieldValues
|_ isFriday: true/false
Subscribe to Topic Changes
The final part of the code is to subscribe to updates to the topic map and update the checkbox if the related map is changed.
This is also done in the activation callback so that the subscription is opened only when the view is actually used.
It is also necessary to return the registration of the listener so it can be removed when the component is detached to avoid leaking memory.
Source code
TopicView.java
package com.vaadin.demo.ce;
import com.vaadin.collaborationengine.CollaborationEngine;
import com.vaadin.collaborationengine.CollaborationMap;
import com.vaadin.collaborationengine.UserInfo;
import com.vaadin.flow.component.UI;
import com.vaadin.flow.component.checkbox.Checkbox;
import com.vaadin.flow.component.orderedlayout.VerticalLayout;
import com.vaadin.flow.router.Route;
import com.vaadin.flow.shared.Registration;
@Route(value = "ce/topic", layout = MainView.class)
public class TopicView extends VerticalLayout {
private final Checkbox checkbox;
public TopicView() {
checkbox = new Checkbox("Is it Friday?");
add(checkbox);
// NOTE: In a real application, use the user id of the logged in user
// instead
String userId = System.identityHashCode(UI.getCurrent()) + "";
UserInfo localUser = new UserInfo(userId, "User " + userId);
CollaborationEngine.getInstance().openTopicConnection(this, "tutorial",
localUser, topic -> {
CollaborationMap fieldValues = topic
.getNamedMap("fieldValues");
Registration registration = checkbox
.addValueChangeListener(valueChangeEvent -> {
fieldValues.put("isFriday",
valueChangeEvent.getValue());
});
fieldValues.subscribe(event -> {
if ("isFriday".equals(event.getKey())) {
checkbox.setValue(Boolean.TRUE
.equals(event.getValue(Boolean.class)));
}
});
return registration;
});
}
}
Tip
Combining registrations
In case there are many registrations, they can be combined by Registration.combine(registration1, registration2);.
Run the Application
Follow instructions in the application’s README.md file to start the application.
Open http://localhost:8080/ in multiple browser tabs to see how a change made in one tab is automatically shown in the other tabs.