Setting Up for Production
Enabling production mode for a Vaadin application is described in Deploying to Production. If your application uses Collaboration Engine, it requires some extra steps when you take your application to production. These steps are described here.
Before configuring your Vaadin application for production mode, you need to:
-
Get a license file with a user quota.
-
Configure where Collaboration Engine files are stored.
-
Store the license file in the right location.
-
Implement a
LicenseEventHandler
to get notified when the license needs to be updated.
Obtaining a Free "Universal" License File
All Vaadin applications receive a free 20 users per month quota with a universal license file. If you don’t have a commercial Vaadin subscription (Pro, Prime, or Enterprise), you can download the universal license file.
The name of the license file is ce-license.json
.
It informs Collaboration Engine that you are entitled to receive a quota of 20 users per month.
You can upgrade to a commercial license to increase your monthly user quota.
Obtaining a Commercial License File
If you need to use Collaboration Engine powered features for more than 20 users / month, please request a commercial license file.
First, you need to have a commercial Vaadin subscription (Pro, Prime, or Enterprise) to request this license. Each Vaadin subscription offers a bundled quota of users per month. Visit, the official feature page to learn more about the bundled quotas.
To obtain your license, contact our team. You can also request and purchase a larger quota of users than provided by your commercial Vaadin subscription. A starting package for 199 EUR / 500 users / month is available without the need for any other Vaadin commercial subscription.
The name of the license file is ce-license.json
.
It defines how many unique users can use collaborative features per month and when the license expires.
Configuring File Storage Location
Follow the steps in this section after you receive your license file.
You need to configure which directory should be used by Collaboration Engine to store files by setting the vaadin.ce.dataDir
property.
In version 2, the only file that Collaboration Engine uses is the ce-license.json
, but in upcoming versions can use the directory to store automatic usage statistics, topic data, and so forth.
You can configure the directory path by either:
-
configuring the data directory in project files or
-
passing it in as a parameter on the server startup.
If both are present, the server startup parameter is used.
Configuring the Data Directory in Project Files
Storing the path into the project files is a good way if you always deploy your application into the same environment and the folder does not change.
You can set the path as a system property in a VaadinServiceInitListener
, which runs once on server startup.
Spring Applications
If you have a Spring application, you can register a VaadinServiceInitListener
by implementing the interface and annotating the class as a @SpringComponent
.
In the serviceInit
method, you can then set vaadin.ce.dataDir
as a system property.
@SpringComponent
public class MyVaadinInitListener implements VaadinServiceInitListener {
@Override
public void serviceInit(ServiceInitEvent serviceEvent) {
System.setProperty("vaadin.ce.dataDir",
"/Users/steve/vaadin/collaboration-engine/");
}
}
Other Applications
If you have a non-Spring application, you can implement the VaadinServiceInitListener
in the same way as seen above, except that you can’t use the @SpringComponent
annotation.
Instead, you need to register it through the Java Service Provider Interface (SPI) loading facility.
You can do that by providing a file, src/main/resources/META-INF/services/com.vaadin.flow.server.VaadinServiceInitListener
with a fully qualified class name to your listener as content, for example, com.company.myapp.MyVaadinInitListener
.
com.company.myapp.MyVaadinInitListener
Configuring the Data Directory on Server Startup
For another way, you can pass the data directory as a parameter on server startup. This way assumes that you have already a production-ready build available and want to run the package on the server. Read Deploying to Production to learn more about building your application for production.
Spring Boot Applications
You can set the data directory with the vaadin.ce.dataDir
system property for Java, for example as follows on the command line:
java -Dvaadin.ce.dataDir=/Users/steve/.vaadin/collaboration-engine -jar my-app-1.0-SNAPSHOT.jar
Note that the system property should be before the -jar
parameter.
Other Servlet Containers
You can pass the data directory parameter as a context parameter to the servlet container.
You should refer to your servlet container’s documentation on how to provide it.
You need to set the vaadin.ce.dataDir
context parameter.
The value should be the directory path.
For example, you can pass the context parameter to Jetty as follows:
mvn jetty:run -Dvaadin.ce.dataDir=/Users/steve/vaadin/collaboration-engine/
See Runtime Configuration for more information.
The directory should be both readable and writable by the user running the Vaadin application.
Placing the License File
After obtaining the license file and the data directory, you need to put the license file in that directory on the server.
For example, if you configured the folder to be /Users/steve/vaadin/collaboration-engine/
, you should place the license file so that the application can read it as /Users/steve/vaadin/collaboration-engine/ce-license.json
.
Collaboration Engine uses the file to verify that you have a proper license. The application does not require an internet connection to Vaadin servers to verify the license.
Providing a Data Directory for a Docker Container
It is recommended to provide the data directory to a Docker container on runtime by either using a volume or a bind mount. It is not recommended to copy the license file into the container image, as the data directory is erased every time you deploy a new version of your application.
If you are deploying to a cloud provider, you may not have access to the host file system to be able to make use of bind mounts. Consult the documentation for your cloud provider to get instructions on how to set up and provide a volume to your application.
While a volume is preferred, if you have access to the host’s file system or want to test the Docker image locally, you can do it with a bind mount with the following steps:
-
Set up a data directory on the host’s file system. For example:
/Users/steve/.vaadin/collaboration-engine
. -
Copy the
ce-license.json
file into the folder above. -
Pick a suitable folder within your Docker image where the container mounts the host folder. For example:
/usr/app/ce
. -
Configure your
Dockerfile
to start up the server with thevaadin.ce.dataDir
parameter pointing to the internal folder. For exampleCMD java -Dvaadin.ce.dataDir=/usr/app/ce -jar /usr/app/app.jar
-
Build the Docker image, for example
$ docker build --tag my-app .
in the project directory. -
Start up the Docker container by giving the
-v
parameter mapping the host folder to the image folder. For example$ docker run --name=myapp -dp 8080:8080 -v /Users/steve/.vaadin/collaboration-engine:/usr/app/ce myapp
When using volumes, you would replace the absolute path to the directory with the name of the volume, for example:
$ docker run --name=myapp -dp 8080:8080 -v myapp-volume:/usr/app/ce myapp
Notifications for Updating the License
The licensing model may cause collaborative features to be disabled for some of your application’s users. To avoid this situation, you need to get a new license if your old license is about to expire, or if your user base increases and the number of users exceeds the quota for one month.
To know when to update the license, you need to implement a license event handler for Collaboration Engine. Collaboration Engine can fire the following types of license events, each at most once during the license’s lifecycle:
-
the first time when exceeding the user quota and entering the grace period (more details in Going Over the Quota),
-
when the grace period ends,
-
30 days before the license expires, and
-
when the license expires.
If you take care of updating the license when events 1 and 3 are fired, the other two events shouldn’t happen at all.
One potential way to handle the event is to send a message to any existing application monitoring system you might have. Another option is to send an email to the relevant people, for example, those who maintain the deployment and those who are responsible of the Collaboration Engine license. You need to ensure that your application notices and handles the events.
The listener can be configured in a VaadinServiceInitListener
in the same way as the vaadin.ce.dataDir
property,
if you’re setting that property in Java code, as described earlier.
The following example is a Spring project, so the VaadinServiceInitListener
is registered by adding the @SpringComponent
annotation.
If you are not using Spring, you can register the service init listener in the same way as described in Configuring the Data Directory in Project Files.
@SpringComponent
public class MyVaadinInitListener implements VaadinServiceInitListener {
private static final Logger LOGGER = LoggerFactory
.getLogger(MyVaadinInitListener.class);
@Override
public void serviceInit(ServiceInitEvent serviceEvent) {
System.setProperty("vaadin.ce.dataDir",
"/Users/steve/vaadin/collaboration-engine/");
VaadinService service = serviceEvent.getSource();
LicenseEventHandler licenseEventHandler = licenseEvent -> {
switch (licenseEvent.getType()) {
case GRACE_PERIOD_STARTED:
case LICENSE_EXPIRES_SOON:
LOGGER.warn(licenseEvent.getMessage());
break;
case GRACE_PERIOD_ENDED:
case LICENSE_EXPIRED:
LOGGER.error(licenseEvent.getMessage());
break;
}
sendEmail("Vaadin Collaboration Engine license needs to be updated",
licenseEvent.getMessage());
};
CollaborationEngineConfiguration configuration = new CollaborationEngineConfiguration(
licenseEventHandler);
CollaborationEngine.configure(service, configuration);
}
}
In the above example, the license event handler logs the event messages using the SLF4J logging API, and sends an email. When it is time to update the license, the message is logged as a warning. If the license is not updated in time, the message is logged as an error. The default event messages provide information of what has happened, how it affects the application, and what is the recommended action to take.
Below is an example implementation of the sendEmail()
method.
It requires the javax.mail.mail
package as a dependency.
private void sendEmail(String subject, String content) {
// Replace the following information:
String from = "sender@gmail.com";
String password = "*****"; // Read, for example, from encrypted config
// file.
String to = "receiver@gmail.com";
String host = "smtp.gmail.com";
Properties properties = System.getProperties();
properties.put("mail.smtp.host", host);
properties.put("mail.smtp.port", "465");
properties.put("mail.smtp.ssl.enable", "true");
properties.put("mail.smtp.auth", "true");
Session session = Session.getInstance(properties, new Authenticator() {
@Override
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication(from, password);
}
});
try {
MimeMessage message = new MimeMessage(session);
message.setFrom(new InternetAddress(from));
message.addRecipient(Message.RecipientType.TO,
new InternetAddress(to));
message.setSubject(subject);
message.setText(content);
Transport.send(message);
} catch (MessagingException e) {
LOGGER.error(e.getMessage(), e);
}
}
Note
|
Exception thrown if events are not handled
Collaboration Engine throws an exception in production mode if a configuration has not been defined.
The purpose is to make sure that your application handles the events,
and to avoid situation where the license expires by accident.
|
User Quota
Your license includes a quota for how many unique users are supported within a month, for example, a limit of 1.000 users. Collaboration Engine counts how many users use its features during each calendar month. The count of users starts over on the first day of each month.
Definition of a User
When you use any Collaboration Engine features, you have to provide a
UserInfo
object with a unique ID.
String userId = "steve@example.com";
String name = "Steve";
UserInfo userInfo = new UserInfo(userId, name);
CollaborationAvatarGroup avatarGroup = new CollaborationAvatarGroup(
userInfo, "app");
add(avatarGroup);
Collaboration Engine records the ID of each user that accesses collaborative features in the ongoing month and counts towards your quota for the current month. Each user ID is counted only once per month.
Going Over the Quota
When you exceed the limit the first time, nothing changes from the user’s perspective. When that happens, Collaboration Engine starts a 30-day grace period, during which time the quota is ten times bigger. The grace period gives you time to react to exceeding your limit without impacting your application in any way. For example, if you have obtained a license for a 500 user quota, your effective quota is 5.000 users during the grace period. After 30 days, your effective quota goes back to 500, and you won’t get another grace period until the next billing period.
If the number of users in a month exceeds the 10x quota during the grace period, or the normal quota after the grace period is over, the collaborative features are disabled for the exceeding users.
Your application stills continues to work, but CollaborationAvatarGroup
only show the user’s own avatar, and forms built with CollaborationBinder
do not show edits made by other users.
The users who are registered within the allowed quota have collaborative features available throughout the month.
Consider, for example, a situation where you have a quota for 500 users, you have used your grace period, and 520 users have used collaborative features this month. The first 500 users can collaborate throughout the month. Users from 501 through 520 can use the application, but it works as if Collaboration Engine was not in use. They can only see their own presence and edits. When the calendar month changes, counting starts over, and the first 500 users again get full access for the whole month.
Entering the Grace Period
The engine enters the grace period when you have a higher demand than expected when obtaining the license. It is recommended that you get a new license with a higher quota to have collaborative features available for all your users before the grace period expires. Contact Vaadin to get a new license file with a higher quota. You can change your quota at any time. When you replace the license file with the new one, Collaboration Engine resets your grace period. If you exceed your new quota in the future, you again receive a 30 day grace period.
Checking for User Access
You can determine whether a user has access or not by passing a callback to the requestAccess()
method in the CollaborationEngine
instance.
The callback gets an AccessResponse
instance as parameter.
You can call its AccessResponse::hasAccess()
method to find out access.
You can use the status to adapt the UI according to whether the user can use collaborative features.
For example:
UserInfo userInfo = new UserInfo("steve@example.com", "Steve");
CollaborationEngine.getInstance().requestAccess(userInfo, response -> {
component.setVisible(response.hasAccess());
});
Tip
|
Cache the results
To avoid calling this method multiple times per user, it is suggested to cache the result during the login process, for example, in the session.
|
Limiting Collaborative Features to Some Users
Collaboration Engine only counts those users towards the quota whose UserInfo
objects are passed to collaborative features.
You can limit usage to a subset of your users in two different ways:
-
Only use Collaboration Engine in views that you have restricted with user access. For example, if you only use collaborative features in the admin views, only those users who access the admin views are counted.
-
Check the details of the user before initializing the collaboration features. For example, by checking the role or privileges or the user, you can decide in code if the users should have collaborative features enabled or not.
An example of how to enable collaboration by checking user permissions:
User userEntity = userService.getCurrentUser();
if (userEntity.getRoles().contains(Role.ADMIN)) {
UserInfo userInfo = new UserInfo(userEntity.getId(),
userEntity.getName(), userEntity.getImageUrl());
CollaborationAvatarGroup avatarGroup = new CollaborationAvatarGroup(
userInfo, "avatars");
add(avatarGroup);
}
C9E1F3EE-132E-421C-A688-CB930D4B2B10