Using Vaadin with OSGi

Vaadin applications can be deployed on an OSGi compatible servlet container.

An OSGi application typically consists of multiple bundles that can be deployed individually.

To deploy Vaadin applications as OSGi bundles, static resources must be published using the appropriate APIs.

The application is typically packaged as a JAR file, and needs to have a valid OSGi bundle manifest which can be created, for example, by the bnd-maven-plugin or Apache Felix maven-bundle-plugin. All the dependencies of the application should be available as OSGi bundles.

Minimal Vaadin Project for OSGi

Vaadin application for OSGi should be a valid bundle. That is, it should be packaged as a .jar file, and it should have a proper OSGi manifest inside. The easiest way to convert regular Maven-based Vaadin application into a valid OSGi bundle consists of five steps:

  1. Change packaging type to jar in your pom.xml:

        <packaging>jar</packaging>
  2. Change the scope for all Vaadin dependencies from default to provided, like this:

        <dependency>
            <groupId>com.vaadin</groupId>
            <artifactId>vaadin</artifactId>
            <scope>provided</scope>
        </dependency>
  3. Add OSGi-related dependencies to the project

        <dependency>
            <groupId>com.vaadin</groupId>
            <artifactId>flow-osgi</artifactId>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>org.osgi</groupId>
            <artifactId>osgi.core</artifactId>
            <version>7.0.0</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>org.osgi</groupId>
            <artifactId>osgi.cmpn</artifactId>
            <version>7.0.0</version>
            <scope>provided</scope>
        </dependency>

flow-osgi version is defined in vaadin-bom, which comes from com.vaadin:vaadin dependency.

+ . Setup necessary plugins for building the project:

+

 <build>
    <plugins>
        <plugin>
            <groupId>biz.aQute.bnd</groupId>
            <artifactId>bnd-maven-plugin</artifactId>
            <version>3.3.0</version>
            <executions>
                <execution>
                    <goals>
                        <goal>bnd-process</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-jar-plugin</artifactId>
            <version>3.0.2</version>
            <configuration>
                <archive>
                    <manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile>
                </archive>
            </configuration>
        </plugin>
        ...
    </plugins>
</build>

+ . Add bundle script (bnd.bnd) into the project root folder:

+

Bundle-Name: ${project.name}
Bundle-Version: ${project.version}
Bundle-SymbolicName: ${project.groupId}.${project.artifactId}
Export-Package: com.example.osgi.myapplication
Import-Package: *
Vaadin-OSGi-Extender: true

+ The last line in the manifest tells Vaadin OSGi integration to scan all classes in the bundle and discover routes.

Make a production build of the project (see Deploying to Production) which means that frontend resources are compiled into a bundle (using build-frontend Vaadin maven plugin goal) and packaged together with Java code into the resulting project JAR.

Note
At the moment Vaadin web application may be used only with bundled frontend resources. webpack development mode is not supported.

Publishing a Servlet With OSGi

It is the developer’s responsibility to register a VaadinServlet in the servlet container, inside OSGi container. One way to do that is to use HTTP Whiteboard specification.

import javax.servlet.Servlet;
import javax.servlet.ServletException;

import org.osgi.service.component.annotations.Component;
import org.osgi.service.http.whiteboard.propertytypes.HttpWhiteboardServletAsyncSupported;
import org.osgi.service.http.whiteboard.propertytypes.HttpWhiteboardServletPattern;

import com.vaadin.flow.server.VaadinServlet;

@Component(service = Servlet.class)
@HttpWhiteboardServletAsyncSupported
@HttpWhiteboardServletPattern("/*")
public class FixedVaadinServlet extends VaadinServlet {

     @Override
     public void init(ServletConfig servletConfig) throws ServletException {
         super.init(servletConfig);

         getService().setClassLoader(getClass().getClassLoader());
     }

}
Note
FixedVaadinServlet class is used here as a workaround for the Classloader bug.

When you have more than one bundle created by Vaadin, note that you should not have multiple VaadinServlet registrations with the same servlet pattern. You should either use a unique pattern for each bundle or create VaadinServlet in only one bundle. In the latter case, keep in mind that for the other bundles to work, it is required that the bundle containing the servlet is active.

Class Discovery

Vaadin discovers many classes to delegate them some functionality. For example, classes annotated with @Route annotation are used in the routing functionality (see Defining Routes with @Route). Many other classes require discovery as well (see also Router Exception Handling, PWA Configuration). It doesn’t happen out of the box in OSGi container for every bundle.

To avoid scanning all classes in all bundles Vaadin uses Vaadin-OSGi-Extender manifest header as a marker for those bundles that needs to be scanned. If you have a bundle which contains routes or other classes whose functionality relies on inheritance or annotation presence you should mark this bundle using Vaadin-OSGi-Extender manifest header. Every Vaadin application bundle should have this manifest header. Otherwise routes declared in the bundle won’t be discovered:

Export-Package: com.example.osgi.myapplication
Import-Package: *
Vaadin-OSGi-Extender: true

Deployment to OSGi Container

To have your application running under OSGi container, you need to have Vaadin Flow bundles deployed, and then the application bundle can be deployed and started. Please note that there are many transitive dependencies which are also need to be deployed. The bundle won’t be activated if all its dependencies are not deployed and activated (it might be that some OSGi containers may deploy transitive dependencies along with the bundle deployment).

Here is a minimal list of required Vaadin Flow bundles:

  • flow-server-X.Y.Z.jar

  • flow-client-X.Y.Z.jar

  • flow-html-components-X.Y.Z.jar

  • flow-data-X.Y.Z.jar

  • flow-osgi-X.Y.Z.jar

This is not a full list of all required bundles. The full list is too long and may vary due to transitive dependencies. Here are some required external dependencies (the versions are omitted):

  • jsoup

  • gentyref-x.y.z.vaadin1.jar

  • gwt-elemental-x.y.z.vaadin2.jar

  • ph-css

Please note that some dependencies are repackaged by Vaadin because the original jars are not OSGi compatible (like gwt-elemental).

Other dependencies require some OSGi features which needs to be deployed at runtime but they do not depend on them during compilation.

This is the case with ph-css bundle. It depends on ph-commons (which should be deployed also) but the latter bundle requires ServiceLoader OSGi implementation. You need to deploy the bundle which contains this implementation suitable for your OSGi container.

Vaadin OSGi support uses OSGi Compendium API, which allows registering an OSGi service using declarative services annotations. If your OSGI container doesn’t have it out of the box, you have to deploy an implementation bundle to support the Compendium API.

If you want to use some ready-made Vaadin components like Vaadin Button, you should deploy the vaadin-button-flow bundle as a dependency.

OSGi Base Starter

An OSGi base starter project is available at https://github.com/vaadin/base-starter-flow-osgi. This project consists of two modules: starter and app.

The starter project is a Vaadin web application bundle project which is packaged as a JAR and may be deployed to any OSGi container.

The app project contains configuration which allows you to run the starter project in an OSGi container. Please refer to the README.md file in the project for details.

Vaadin Component Version Updates

A Vaadin application contains dependencies to other bundles, for example, Vaadin components like Button, TextField, etc.

Every Vaadin component is based on a Web Component which is represented by frontend resources. All frontend resources get built into a bundle along with Vaadin WAB. As a result:

  • Any Vaadin component bundle update is possible only within the same minor version, so that the Web Component version stays the same (and only Java code is updated).

    Avoid updating any version over a minor for Flow or the web component Flow integrations (even though it’s not prevented at the moment).

  • Updating any bundle that has frontend resources requires running the frontend build goal build-frontend and the WAB is redeployed to get the static frontend bundle updated.

Limitations

  • npm development mode: it’s only possible to run Vaadin web application in production mode (with frontend resources bundled into the JAR)

  • You can’t use OSGi declarative services with Vaadin components: you may not inject a service declaratively in Vaadin classes (using annotations) because UI objects are not managed by OSGi. But you may still call OSGi services programmatically.

  • No yet automatic servlet registration. The web application bundle should register the servlet itself.

  • Push does not work with WebSockets. It is not clear how to enable WebSockets for a pure OSGi container. It works on hybrid OSGi containers which allow to deploy WARs (like Karaf) but this is the same as for plain web servers.

  • Fusion/TypeScript views can’t be used in OSGi