Documentation

Documentation versions (currently viewingVaadin 24)

Creating Vaadin Portlets

How to build and run your own Vaadin Portlets.

This section describes how to create Vaadin Portlets and how to deploy them to the Liferay 7 Digital Experience Platform.

Creating a Vaadin Portlet

You can create a Vaadin Portlet either from scratch, or from the base-starter-flow-portlet project. The starter project contains everything needed to create your own Vaadin Portlet, quickly. It includes the basic code you’ll need.

To become familiar with setting up a Vaadin Portlet project, start with a simple Vaadin project and then convert it into a Vaadin Portlet project.

Portlet Project Set Up

First, download the Vaadin base starter. Then, update your pom.xml file by adding the following dependencies:

+ .pom.xml additions

<dependency>
    <groupId>com.vaadin</groupId>
    <artifactId>vaadin-portlet</artifactId>
    <version>1.0.0</version>
</dependency>

+

<dependency>
    <groupId>javax.portlet</groupId>
    <artifactId>portlet-api</artifactId>
    <version>3.0.1</version>
    <scope>provided</scope>
</dependency>

Vaadin Portlet doesn’t work in development mode running vaadin-dev-server. Therefore, add a build-frontend goal to vaadin-maven-plugin.

Create the Portlet

In the most basic setup, Vaadin Portlets consist of two classes. First, there’s a portlet class, which extends VaadinLiferayPortlet or VaadinPortlet — when running in non-Liferay Portal. It acts as the entry point for your Vaadin Portlet application. It serves a similar function to a Servlet, but in a portlet context.

Second, there’s a portlet view class, which extends Component. The view class, which can be any normal Vaadin component, contains the contents of your Vaadin Portlet. You could use an existing component through extension, composition, or as it is. Or you can create an entirely new component for your Vaadin Portlet. VaadinPortlet and VaadinLiferayPortlet are generic classes. They take the selected view class as a type parameter.

Class Preparations

Find the MainView.java provided with the project and create a file named MyPortlet.java in the same folder. Inside that file, add the following code:

@PortletConfiguration(
    portletName = "MyLiferayPortlet",
    dependencies = @Dependency(name = "PortletHub", scope = "javax.portlet", version = "3.0.0")
)
public class MyLiferayPortlet extends VaadinLiferayPortlet<MainView> {

}
public class MyPortlet extends VaadinPortlet<MainView> {

}

Next, open the MainView.java file. Remove both the @Route and @PWA annotations since they won’t make sense for your portlet.

The final code should look something like this:

public class MainView extends VerticalLayout {

    public MainView() {
        Button button = new Button("Click me",
                event -> Notification.show("Clicked!"));
        add(button);
    }
}

When a user clicks on the Click me button, a notification with the text Clicked! should appear in the lower-left corner of the browser window. Your Vaadin Portlet is almost ready to go. You only need to prepare it for deployment.

Deployment Descriptor

In the Portlet 3.0 specification, the portlet deployment descriptor can be configured in two ways: with portlet.xml, which is backwards-compatible; and with annotations, which is available only with Portlet 3.0.

You’ll use the portlet.xml file to configure your portlet deployment. It serves the same purpose as the web.xml file for servlets.

Create the portlet.xml file in the {project directory}/src/main/webapp/WEB-INF directory and add the following content:

<?xml version="1.0"?>
<portlet-app xmlns="http://xmlns.jcp.org/xml/ns/portlet"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/portlet http://xmlns.jcp.org/xml/ns/portlet/portlet-app_3_0.xsd"
             version="3.0">
    <portlet>
        <portlet-name>MyLiferayPortlet</portlet-name>
        <display-name>MyLiferayPortlet</display-name>
        <portlet-class>org.vaadin.example.MyPortlet</portlet-class>
        <expiration-cache>0</expiration-cache>
        <supports>
            <mime-type>text/html</mime-type>
            <portlet-mode>view</portlet-mode>
        </supports>
        <portlet-info>
            <title>My Test Portlet - MyPortlet</title>
            <short-title>My Test Portlet</short-title>
            <keywords></keywords>
        </portlet-info>
    </portlet>
</portlet-app>

The <portlet-class> points to your class extending VaadinPortlet/VaadinLiferayPortlet with a fully qualified name. The <supports> section contains the portlet modes (i.e., <portlet-mode> tag) that the portlet supports. You can learn more about portlet modes for Vaadin Portlet in the next article.

Descriptors Specific to Liferay

To run Vaadin Portlets in Liferay Portal, you’ll need to set portlet descriptors that are specific to Liferay: liferay-display.xml and liferay-portlet.xml.

The descriptor, liferay-display.xml describes the category under which the portlet appears in the Add menu of Liferay’s Widgets bar. The descriptor, liferay-portlet.xml describes Liferay-specific enhancements for Java Specification Requests (JSR) 286 portlets installed on a Liferay Portal server.

Create the liferay-display.xml and liferay-portlet.xml files in the {project directory}/src/main/webapp/WEB-INF directory. Add the following respective content to those files:

<?xml version="1.0"?>
<!DOCTYPE display PUBLIC "-//Liferay//DTD Display 6.2.0//EN" "http://www.liferay.com/dtd/liferay-display_6_2_0.dtd">

<display>
    <category name="Vaadin Liferay Portlets">
        <portlet id="MyLiferayPortlet" />
    </category>
</display>
<?xml version="1.0"?>
<!DOCTYPE liferay-portlet-app PUBLIC "-//Liferay//DTD Portlet Application 7.1.0//EN" "http://www.liferay.com/dtd/liferay-portlet-app_7_1_0.dtd">

<liferay-portlet-app>
    <portlet>
        <portlet-name>MyLiferayPortlet</portlet-name>
        <!-- Instanceable parameter means whether we can add the Portlet more than once on same page.-->
        <instanceable>false</instanceable>
    </portlet>
</liferay-portlet-app>
Note
The instanceable parameter specifies whether the Portlet can be added more than once on the same page. If it’s set to false, it can be added only once on a page.

External Stats URL

Next, you need to set an external stats URL in Liferay. If your portlet runs in Liferay Portal, add the following resource file, flow-build-info.json into {project directory}/src/main/resources/META-INF/VAADIN/config with this content:

{
    "externalStatsUrl": "/o/vaadin-portlet-static/VAADIN/config/stats.json"
}

webpack for Front-End Builds

Starting with Vaadin 23.2, Vite is the default tool for front-end builds. However, Vaadin Portlet requires webpack to be used. To use webpack, you must enable it with the webpackForFrontendBuild feature flag.

com.vaadin.experimental.webpackForFrontendBuild=true

See Feature Flags for more information.

Deploying Your Vaadin Portlet

Assuming all went correctly, you’re now ready to deploy your Vaadin Portlet. First, you’ll have to build it. Then you’ll have to configure static resources. Last, you’ll deploy your Vaadin Portlet to Liferay 7. These steps are described in the following sub-sections.

Building the Vaadin Portlet

To build the portlet you created, you must add some more configuration to the pom.xml file. Vaadin Portlet deployments are packaged into two WAR files. One WAR file contains all of the static resources shared by the Vaadin Portlets, and the other contains the actual portlets. This allows for more complex scenarios where multiple portlets come from separate WAR files (see Creating Multi-Module Portlet Project).

Add the following plugin configuration to the pom.xml file:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-war-plugin</artifactId>
    <version>3.2.3</version>
    <configuration>
        <archive>
            <manifestEntries>
                <Implementation-Title>${project.name}</Implementation-Title>
                <Implementation-Version>${project.version}</Implementation-Version>
            </manifestEntries>
        </archive>
    </configuration>
    <!-- Generate 2 war archives for portlet. One for the portlet(s) and another for the static files -->
    <executions>
        <!-- Generate a static war 'vaadin-portlet-static.war' with all static files -->
        <execution>
            <id>static-files</id>
            <goals>
                <goal>war</goal>
            </goals>
            <configuration>
                <warName>vaadin-portlet-static</warName>
                <!-- static files should contain flow-client and all build files generated in VAADIN/ -->
                <packagingIncludes>WEB-INF/lib/flow-client*.jar,WEB-INF/lib/vaadin-portlet*.jar,VAADIN/</packagingIncludes>

                <webResources>
                    <resource>
                        <!-- this is relative to the pom.xml directory -->
                        <directory>target/classes/META-INF/VAADIN/webapp/</directory>
                        <!-- Include all files and folders below <directory> -->
                        <includes>
                            <include>**</include>
                        </includes>
                    </resource>
                    <resource>
                        <!-- this is relative to the pom.xml directory -->
                        <directory>target/classes/META-INF/</directory>
                        <!--
                            Include all config files to root except flow-build-info
                            that is not needed at runtime when running fronted builds
                        -->
                        <includes>
                            <include>VAADIN/config/**</include>
                        </includes>
                        <!-- do not include  file as it contains portlet configuration -->
                        <excludes>
                            <exclude>VAADIN/config/flow-build-info.json</exclude>
                        </excludes>
                    </resource>
                </webResources>
            </configuration>
        </execution>
        <!-- Generate the portlet war excluding any static build files -->
        <execution>
            <id>portlet-war</id>
            <goals>
                <goal>war</goal>
            </goals>
            <configuration>
                <primaryArtifact>true</primaryArtifact>
                <packagingExcludes>WEB-INF/classes/META-INF/webapp/VAADIN/build/**,VAADIN/</packagingExcludes>
                <webResources>
                    <resource>
                        <directory>${project.basedir}/src/main/resources/</directory>
                        <!--
                        Include original flow-build-info.json, not the one produced by vaadin plugin
                        and included in the static portlet
                        -->
                        <includes>
                            <include>META-INF/VAADIN/config/flow-build-info.json</include>
                        </includes>
                        <targetPath>WEB-INF/classes/</targetPath>
                    </resource>
                </webResources>
            </configuration>
        </execution>
    </executions>
</plugin>

In this example, you’re building two WAR files: one for the application (i.e., all portlets in the project); and the other for the static files needed by the portlets, which contains the front-end bundle and client engine.

The static WAR is built as a portal window that can load only a single Vaadin bundle and client engine at a time. This provides a simple way for all of the portlets on the page to use the same static bundle.

Configuring Static Resources

If you need to change the name of the static assets WAR — by default it’s vaadin-portlet-static — you can do so via the vaadin.portlet.static.resources.mapping application property. For example, if you want to serve static resources from vaadin-static-resources.war, you need do the following:

  • Rename the static WAR to vaadin-static-resources in the pom.xml file;

  • Change the static portlet name in the flow-build-info.json file — if Liferay is used; and

  • Pass the value /vaadin-static-resources/ — for Liferay Portal, it would be /o/vaadin-portlet-resources/ — via the application property to the Vaadin application.

For this last step, on the Tomcat web server you would do things a little differently, depending on the operating system:

  • On Unix-based operating systems, create or edit the file $CATALINA_BASE/bin/setenv.sh with this line:

JAVA_OPTS="$JAVA_OPTS -Dvaadin.portlet.static.resources.mapping=/vaadin-static-resources/"
  • On Windows operating systems, create or edit the file %CATALINA_BASE%\bin\setenv.bat with this line:

set "JAVA_OPTS=%JAVA_OPTS% -Dvaadin.portlet.static.resources.mapping=/vaadin-static-resources/"

Deploying to Liferay 7

The last major step for your Vaadin Portlet is to deploy it to Liferay 7. To do this, there are a few system and software requirements. Then you’ll have to add some property files and do some configuring.

System & Software Requirements

First, execute mvn install in your project directory. Then download Liferay Bundle and extract it to a location you prefer.

Add the following parameter to Liferay Tomcat’s setenv.sh file, located in {liferay home}/tomcat-<version>/bin:

-Dvaadin.portlet.static.resources.mapping=/o/vaadin-portlet-static/

Now download and copy the Java Native Access (JNA) JAR dependencies for the specific version into {liferay home}/tomcat-<version>/webapps/ROOT/WEB-INF/lib — or shielded-container-lib, depending on the version: - net.java.dev.jna:jna:5.7.0; or - net.java.dev.jna:jna-platform:5.7.0.

This is needed because Vaadin Portlet uses a newer version of the JNA library, which can cause conflicts with the version that Liferay uses.

Property Files & Configurations

Create a portal-ext.properties file in Liferay’s home directory and put this property in it:

javascript.single.page.application.enabled=false

Copy both WAR files from {project directory}/target into {liferay home}/deploy.

Next, start the web server by opening a command prompt in the {bundle extract directory} folder and then executing ./{tomcat-version}/bin/startup.sh on Unix systems, or ./{tomcat-version}/bin/startup.bat on Windows.

Once the web server has started, navigate to http://localhost:8080/ and follow the instructions of the Liferay wizard to set up a new user and sign in to the Portal. In the Portal are only a few more steps:

  1. Click the "Menu" button at the top-left corner to open the menu console.

  2. Find and click the "Page tree" link and then the "+" button to add a new page.

  3. Select "Widget Page", give it a name, and then select the appropriate layout.

  4. In the "Look and Feel" tab, select "Define a specific look and feel for this page", and enable "Show Maximize/Minimize" and then "Save".

Finally, navigate to the home page, then to the layout you created. Click the "Add" button, which is usually placed at the top-right corner, and find the category "Vaadin Liferay Portlets". Open it and drag the portlet item from the panel to the page. You should see the portlet with the title MY TEST PORTLET - MYPORTLET and a Click me button in the content area.

DBCCB99A-428F-4A13-AA7E-BDD0AFB0531B