Using Vaadin with OSGi
Note
|
Commercial feature
A commercial Vaadin subscription is required to use the OSGi plugin in your project. |
Vaadin applications can be deployed in 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
A Vaadin application for OSGi should be a valid bundle.
That is, it should be packaged as a JAR
file, and should have a proper OSGi manifest inside.
The easiest way to convert a regular Maven-based Vaadin application into a valid OSGi bundle consists of five steps:
-
Change the packaging type to
jar
in yourpom.xml
:<packaging>jar</packaging>
-
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>
-
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>
NoteThe
flow-osgi
version is defined invaadin-bom
, which comes from thecom.vaadin:vaadin
dependency. -
Set up the 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 the 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 front-end resources are compiled into a bundle (using the build-frontend
Vaadin Maven plugin goal) and packaged together with Java code into the resulting project JAR
.
Note
|
Currently, a Vaadin web application may be used only with bundled front-end resources.
vite development mode isn’t supported.
|
Publishing a Servlet with OSGi
It’s the developer’s responsibility to register a VaadinServlet
in the servlet container, inside the OSGi container.
One way to do this is to use the 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
|
The FixedVaadinServlet class is used here as a workaround for the
class loader bug.
|
When you have more than one bundle created by Vaadin, you shouldn’t 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 this case, keep in mind that for the other bundles to work, it’s required that the bundle containing the servlet should be active.
Class Discovery
Vaadin discovers many classes to delegate some functionality to them.
For example, classes annotated with @Route
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 for every bundle in the OSGi container.
To avoid scanning all classes in all bundles, Vaadin uses the Vaadin-OSGi-Extender
manifest header as a marker for those bundles that need to be scanned.
If you have a bundle which contains routes, or other classes whose functionality relies on inheritance or the presence of an annotation, you should mark this bundle using the Vaadin-OSGi-Extender
manifest header.
Every Vaadin application bundle should have this manifest header, otherwise routes declared in the bundle aren’t 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. The application bundle can then be deployed and started. Many transitive dependencies also need to be deployed. The bundle isn’t activated unless all its dependencies are deployed and activated. Some OSGi containers might deploy transitive dependencies along with the bundle deployment.
Here is a minimal list of the 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 isn’t a full list of all the 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
-
…
Some dependencies are repackaged by Vaadin because the original JARs
aren’t OSGi-compatible (such as gwt-elemental
).
Other dependencies require some OSGi features that need to be deployed at runtime, but they don’t depend on them during compilation.
This is the case with the ph-css
bundle.
It depends on ph-commons
(which should also be deployed) but this bundle requires the ServiceLoader
OSGi implementation.
You need to deploy the bundle which contains the appropriate implementation for your OSGi container.
Vaadin OSGi support uses the OSGi Compendium API, which allows you to register an OSGi service using declarative services annotations. If your OSGi container doesn’t have it out of the box, you need to deploy an implementation bundle to support the Compendium API.
If you want to use some ready-made Vaadin components, such as 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 that’s packaged as a JAR
and may be deployed to any OSGi container.
The app
project contains a configuration that allows you to run the starter
project in an OSGi container.
See the README.md file in the project for details.
Vaadin Component Version Updates
A Vaadin application contains dependencies on other bundles, for example, Vaadin components such as Button
,
TextField
, etc.
Every Vaadin component is based on a Web Component which is represented by front-end resources.
All front-end resources get built into a bundle along with the 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 the Java code is updated).
Avoid updating any version greater than a minor for Flow or the web component Flow integrations (even though this isn’t currently prevented).
-
Updating any bundle that has front-end resources requires running the front-end build goal
build-frontend
, and theWAB
is redeployed to cause the static front-end bundle to be updated.
Limitations
-
npm
development mode: it’s only possible to run a Vaadin web application in production mode (with front-end resources bundled into theJAR
) -
You can’t use OSGi declarative services with Vaadin components. You can’t inject a service declaratively in Vaadin classes (using annotations), because UI objects aren’t managed by OSGi. However, you can still call OSGi services programmatically.
-
Automatic servlet registration is unavailable. The web application bundle needs to register the servlet itself.
-
Push doesn’t work with WebSockets. It isn’t clear how to enable WebSockets for a pure OSGi container. It works on hybrid OSGi containers that allow you to deploy
WARs
(such as Karaf), but this is the same as for plain web servers.