Production Configuration
- Getting a Free "Universal" License File
- Getting a Commercial License File
- Configuring File Storage Location
- Placing the License File
- Providing a Data Directory for a Docker Container
- Notifications for Updating the License
- User Quota
Enabling production mode for a Vaadin application is described in Deploying to Production. If your application uses Collaboration Kit, 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 Kit files are stored.
-
Store the license file in the right location.
-
Implement a
LicenseEventHandler
to get notified when the license needs to be updated.
Getting 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 Kit 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.
Getting a Commercial License File
If you need to use Collaboration Kit powered features for more than 20 users / month, 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 get your license, contact Vaadin. You can also request and purchase a larger quota of users than provided by your commercial Vaadin subscription. A starting package for 199 € / 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 Kit to store files by setting the vaadin.ce.dataDir
property.
This directory is used by Collaboration Kit to automatically store usage data to keep track of users for each month.
You should also put your ce-license.json
file in the same directory for Collaboration Kit to find it.
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 doesn’t change.
Spring Applications
If you have a Spring application, you can provide a bean of type CollaborationEngineConfiguration
from your main Spring class by annotating a method with the @Bean
annotation and returning a configuration instance with the data directory path set using the setDataDir
method.
@Bean
public CollaborationEngineConfiguration ceConfigBean() {
CollaborationEngineConfiguration configuration = new CollaborationEngineConfiguration(
licenseEvent -> {
// See <<ce.production.license-events>>
});
configuration.setDataDir("/Users/steve/vaadin/collaboration-engine/");
return configuration;
}
Other Applications
If you have a non-Spring application, you can implement a VaadinServiceInitListener
where you create a CollaborationEngineConfiguration
instance and set it using the CollaborationEngine.configure()
method.
public class MyVaadinInitListener implements VaadinServiceInitListener {
@Override
public void serviceInit(ServiceInitEvent serviceEvent) {
VaadinService service = serviceEvent.getSource();
LicenseEventHandler licenseEventHandler = licenseEvent -> {
// See Notifications for Updating the License
};
CollaborationEngineConfiguration configuration = new CollaborationEngineConfiguration(
licenseEventHandler);
configuration.setDataDir("/Users/steve/vaadin/collaboration-engine/");
CollaborationEngine.configure(service, configuration);
}
}
Then, you need to register the listener via Java Service Provider Interface (SPI) loading facility.
You do this 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
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 see 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 Configuration Properties for more information.
The directory should be both readable and writable by the user running the Vaadin application.
Placing the License File
After getting 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 Kit uses the file to verify that you have a proper license. The application doesn’t require an internet connection to Vaadin servers to verify the license.
Providing a Data Directory for a Docker Container
It’s recommended to provide the data directory to a Docker container on runtime by either using a volume or a bind mount. It isn’t 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 example:java -Dvaadin.ce.dataDir=/usr/app/ce -jar /usr/app/app.jar
-
Build the Docker image, for example (in the project directory):
docker build --tag my-app .
-
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 Kit. Collaboration Kit can fire the following types of license events a maximum of once each during the license’s lifecycle:
-
the first time the user quota is exceeded and the grace period begins (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 Kit license. You need to ensure that your application notices and handles the events.
The listener can be configured when creating the CollaborationEngineConfiguration
as described earlier in Configuring the Data Directory in Project Files.
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 Kit license needs to be updated",
licenseEvent.getMessage());
};
In the above example, the license event handler logs the event messages using the SLF4J logging API, and sends an email. When it’s time to update the license, the message is logged as a warning. If the license isn’t 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’s 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 aren’t handled
Collaboration Kit throws an exception in production mode if a configuration hasn’t been defined.
The purpose is to make sure that your application handles the events,
and to avoid the 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 Kit 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 Kit 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 Kit 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 Kit 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 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 10x the quota during the grace period, or if it exceeds the normal quota after the grace period is over, the collaborative features are disabled for the excess users.
Your application continues to work, but CollaborationAvatarGroup
shows only the user’s own avatar, and forms built with CollaborationBinder
don’t 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 of 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 Kit wasn’t 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 getting the license. It’s 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 Kit 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 by passing a callback to the requestAccess()
method in the CollaborationEngine
instance.
The callback gets an AccessResponse
instance as a parameter.
You can call its AccessResponse::hasAccess()
method to determine the user’s 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’s suggested to cache the result during the login process, for example, in the session.
|
Limiting Collaborative Features to Some Users
Collaboration Kit 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 Kit 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);
}
CD8CDE22-2BF8-43CB-949D-C395BF6CE29B