Vaadin portlets with add-ons in Liferay

by David CaronMarch 27, 2012

The Vaadin web framework has been around for quite some time now, and for a couple of years it also supports portlet development. This is particularly the case for the Liferay portal, where some integration work has already been done for you. Using Vaadin to build Liferay portlets is rather nice, because until you actually become dependent on the Liferay API, your Vaadin project can still run stand-alone, giving you quick feedback during development without having to redeploy the portlet.

Working with Liferay is, like most things in Vaadin, well documented in the “Book of Vaadin”, in chapter 13, but there are some complications. As Vaadin uses GWT under the hood, an application needs a GWT widget set. If you just use standard Vaadin components, the widget set is prepackaged in the war file, but if you start using Vaadin add-ons or custom built components, you need to recompile the widget set. A limitation of running Vaadin portlets is that the widget set needs to be available centrally in the Liferay web application and is shared by all Vaadin portlets. This means that you’ll have to update this widget set in Liferay while your project grows.

The bits of information needed to put this all together are available on the web, but sadly scattered over reference manuals, wikis, blogs and forum posts. In this blog I’ll go through it incrementally. Probably you know most of the steps already, but then again, if you knew them all you wouldn’t be here 😉

Creating a basic Vaadin application

Setting up a basic Vaadin application is of course quite easy. I don’t know any another framework that needs such little configuration.

Firstly, create a basic maven web project. Add the latest Vaadin dependency to your pom.xml.

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>nl.dutchworks.demo</groupId>
    <artifactId>vaadin-demo-portlet</artifactId>
    <version>1.0</version>
    <packaging>war</packaging>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <dependencies>
        <dependency>
            <groupId>com.vaadin</groupId>
            <artifactId>vaadin</artifactId>
            <version>6.7.5</version>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>2.3.2</version>
                <configuration>
                    <source>1.6</source>
                    <target>1.6</target>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

Now create a basic Vaadin “Hello world” type of application; extend the com.vaadin.Application class and override the init() method.

package nl.dutchworks.demo;

import com.vaadin.Application;
import com.vaadin.ui.Label;
import com.vaadin.ui.Window;

public class DemoApplication extends Application {
    @Override
    public void init() {
        Window mainWindow = new Window("Vaadin Demo Application");
        Label label = new Label("Hello Vaadin!");
        mainWindow.addComponent(label);
        setMainWindow(mainWindow);
    }
}

Like most Java web frameworks, Vaadin supplies a servlet as the starting point for the web application. The fully qualified class name of your subclassed application goes in the “application” init-param. The web.xml should look like this:

<?xml version="1.0" encoding="UTF-8"?>
<web-app id="WebApp_ID" version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
    <display-name>Vaadin Demo Application</display-name>
    <context-param>
        <description>Vaadin production mode</description>
        <param-name>productionMode</param-name>
        <param-value>false</param-value>
    </context-param>
    <servlet>
        <servlet-name>vaadin servlet</servlet-name>
        <servlet-class>com.vaadin.terminal.gwt.server.ApplicationServlet</servlet-class>
        <init-param>
            <description>Vaadin Application</description>
            <param-name>application</param-name>
            <param-value>nl.dutchworks.demo.DemoApplication</param-value>
        </init-param>
    </servlet>
    <servlet-mapping>
        <servlet-name>vaadin servlet</servlet-name>
        <url-pattern>/*</url-pattern>
    </servlet-mapping>
</web-app>

Your project directory structure should be looking something like this:

When you build your project with maven and run it on a tomcat configured in your IDE, the output is, unsurprisingly, this:

Using a Vaadin add-on

Now, to add a vaadin add-on let’s take the Event Timeline component.

Firstly, we add the dependency to the pom.xml file:

<dependency>
   <groupId>org.vaadin.addons</groupId>
   <artifactId>event-timeline</artifactId>
   <version>0.5.1</version>
</dependency>

Don’t forget to add the Vaadin add-on maven repository to your artifactory, settings.xml or pom.xml:

<repository>
   <id>vaadin-addons</id>
   <url>http://maven.vaadin.com/vaadin-addons</url>
</repository>

Now, i use the example code provided on the Event Timeline add-on page in the application:

public class DemoApplication extends Application {
    @Override
    public void init() {
        Window mainWindow = new Window("Vaadin Demo Application");
        //Label label = new Label("Hello Vaadin!");
        //mainWindow.addComponent(label);
        setMainWindow(mainWindow);

        EventTimeline timeline = new EventTimeline("Our event timeline");
        timeline.setHeight("500px");
        timeline.setWidth("100%");

        // set the visible time range
        Calendar cal = Calendar.getInstance();
        Date start = cal.getTime();
        cal.add(Calendar.HOUR_OF_DAY, 24);
        Date end = cal.getTime();
        timeline.setVisibleDateRange(start, end);

        // add our data sources
        timeline.addEventBand("Band", createEventProvider(end));

        // Add some zoom levels
        timeline.addZoomLevel("Hour", 60 * 60 * 1000L);
        timeline.addZoomLevel("Day", 86400000L);

        mainWindow.addComponent(timeline);
    }

    public TimelineEventProvider createEventProvider(final Date end) {
        BasicEventProvider provider = new BasicEventProvider();

        // get events for a whole day
        Calendar cal = Calendar.getInstance();
        cal.add(Calendar.HOUR, 1);
        int idx = 0;
        while (cal.getTime().before(end)) {
            // create a simple event
            BasicEvent event = new BasicEvent();
            event.setEventId(String.valueOf(idx));

            // set the timestamp property
            event.setStart(cal.getTime());
            cal.add(Calendar.MINUTE, 10);
            event.setEnd(cal.getTime());
            // set the caption
            event.setCaption("Event");
            // style the event
            event.setStyleName("color1");

            provider.addEvent(event);
            cal.add(Calendar.MINUTE, 30);
            idx++;
        }

        return provider;
    }
}

Of course, running this doesn’t work yet:

Recompiling the widget set

We can fix this by recomping the widget set. For this, we need a couple of steps. The pom.xml file needs quite some additions: We need the gwt-user dependency:

<dependency>
            <groupId>com.google.gwt</groupId>
            <artifactId>gwt-user</artifactId>
            <version>2.3.0</version>
            <scope>provided</scope>
        </dependency>

And then we need to add some plugins.

<plugin>
                <groupId>com.vaadin</groupId>
                <artifactId>vaadin-maven-plugin</artifactId>
                <version>1.0.2</version>
                <executions>
                    <execution>
                        <phase>generate-resources</phase>
                        <configuration>
                            <!-- if you don't specify any modules, the plugin will find them -->
                            <!-- <modules> <module>${package}.gwt.MyWidgetSet</module> </modules> -->
                        </configuration>
                        <goals>
                            <goal>update-widgetset</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
            <!-- Compiles your custom GWT components with the GWT compiler -->
            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>gwt-maven-plugin</artifactId>
                <version>2.3.0-1</version>
                <configuration>
                    <!-- if you don't specify any modules, the plugin will find them -->
                     <webappDirectory>src/main/webapp/VAADIN/widgetsets</webappDirectory>
                    <extraJvmArgs>-Xmx512M -Xss1024k</extraJvmArgs>
                    <runTarget>clean</runTarget>
                    <hostedWebapp>${project.build.directory}/${project.build.finalName}</hostedWebapp>
                    <noServer>true</noServer>
                    <port>8080</port>
                </configuration>
                <executions>
                    <execution>
                        <phase>generate-resources</phase>
                        <goals>
                            <goal>resources</goal>
                            <goal>compile</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>

Then we add a widget set file called VaadinDemoWidgetSet.gwt.xml to our resources directory:

The widgetfile will contain a reference to the default widget set and to the widget set of the add-on (this can be found by inspecting the dependency jar of the add-on).

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE module PUBLIC
        "-//Google Inc.//DTD Google Web Toolkit 2.3.0//EN"
        "http://google-web-toolkit.googlecode.com/svn/tags/2.3.0/distro-source/core/src/gwt-module.dtd">
<module>
    <inherits name="com.vaadin.terminal.gwt.DefaultWidgetSet"/>
    <inherits name="com.spaceapplications.vaadin.addon.eventtimeline.gwt.EventTimelineWidgetSet" />
</module>

Now all that remains to be done is tell Vaadin to actually use the newly generated widget set for this application. This is done by adding an init-param to the servlet definition in the web.xml file:

<servlet>
        <servlet-name>vaadin servlet</servlet-name>
        <servlet-class>com.vaadin.terminal.gwt.server.ApplicationServlet</servlet-class>
        <init-param>
            <description>Vaadin Application</description>
            <param-name>application</param-name>
            <param-value>nl.dutchworks.demo.DemoApplication</param-value>
        </init-param>
        <init-param>
            <param-name>widgetset</param-name>
            <param-value>nl.dutchworks.demo.VaadinDemoWidgetSet</param-value>
        </init-param>
    </servlet>

Building the project with maven and running it now produces the desired result:

Preparing Liferay

The next step is to turn this project into a portlet. For that, we first need to prepare our Liferay instance. Because of the shared nature of widget sets by multiple portlets, the preferred way to use Vaadin in Liferay is with a centralised vaadin.jar and all add-on jar files in the //webapps/ROOT/WEB-INF/lib dir.
To get all the right files in there, and to be able to compile the widget set for the portal, the easiest way is to download and install the Vaadin control panel for Liferay. This portlet installs like all other portlets in liferay.

  • Drop the vaadin control panel war file in your Liferay deploy directory
  • Once deployed, drag the panel onto a page. The settings panel will look like this:

  • The portlet will show which version of Vaadin is in your Liferay, and what’s the latest version out there. Click “Upgrade”; it will download and install the latest Vaadin jar and the GWT jars needed to compile the widget set.
  • Now find the jar file of the add-on, in this case event-timeline-0.5.1.jar (for instance from your .m2/repository directory) and copy it to //webapps/ROOT/WEB-INF/lib.
  • If you click “re-scan” in the control panel it will pick up the add-on jars and allow you to select which ones you want added to the widget set.
  • Now Click the “Compile Widget Set” button. It will compile and put the widget set in the correct place (//webapps/ROOT/html/VAADIN/widgetsets).

Your Liferay instance should now be correctly configured to deploy your application.

Add portlet descriptors to the project

To turn the web project into a portlet project, we need to add a couple of descriptors to the project in /src/main/webapp/WEB-INF. These are the standard portlet.xml and Liferay descriptors. In these Liferay descriptors, the value portlet-name from portlet.xml is used as the portlet id. Further names, titles and descriptions are used by Liferay in various places in the portal GUI (bonus points can be won by finding which ones are used where).

portlet.xml

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<portlet-app xmlns="http://java.sun.com/xml/ns/portlet/portlet-app_2_0.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="2.0" xsi:schemaLocation="http://java.sun.com/xml/ns/portlet/portlet-app_2_0.xsd http://java.sun.com/xml/ns/portlet/portlet-app_2_0.xsd">

    <portlet>
        <portlet-name>Vaadin Demo Portlet</portlet-name>
        <display-name>Vaadin Demo Portlet (portlet.xml display-name)</display-name>

        <portlet-class>com.vaadin.terminal.gwt.server.ApplicationPortlet2</portlet-class>
        <init-param>
            <name>application</name>
            <value>nl.dutchworks.demo.DemoApplication</value>
        </init-param>
        <!-- Supported portlet modes and content types. -->
        <supports>
            <mime-type>text/html</mime-type>
            <portlet-mode>view</portlet-mode>
         </supports>

        <!-- Not always required but Liferay uses these. -->
        <portlet-info>
            <title>Vaadin Demo Portlet title</title>
            <short-title>vaadin-demo-portlet-short-title</short-title>
        </portlet-info>
    </portlet>
</portlet-app>

liferay-portlet.xml

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE liferay-portlet-app PUBLIC "-//Liferay//DTD Portlet Application 6.1.0//EN" "http://www.liferay.com/dtd/liferay-portlet-app_6_1_0.dtd">
<liferay-portlet-app>
    <portlet>
        <!-- Matches definition in portlet.xml. -->
        <!-- Note: Must not be the same as servlet name. -->
        <portlet-name>Vaadin Demo Portlet</portlet-name>
        <instanceable>true</instanceable>
        <ajaxable>false</ajaxable>
    </portlet>
</liferay-portlet-app>

liferay-plugin-package.properties

name=Vaadin Demo Portlet
short-description=Vaadin Demo Portlet short description
module-group-id=Vaadin
module-incremental-version=1
#change-log=
#page-uri=
#author=
license=Proprietary
portal-dependency-jars=\
    vaadin.jar

liferay-display.xml

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE display PUBLIC "-//Liferay//DTD Display 6.1.0//EN" "http://www.liferay.com/dtd/liferay-display_6_1_0.dtd">
<display>
    <category name="Vaadin Portlets">
        <portlet id="Vaadin Demo Portlet"/>
    </category>
</display>

Your project should look like this:

Now, build the project with maven and drop the war file in the Liferay deploy directory. When it’s deployed, you’ll see it appear in the “Add/More…” pop-up in Liferay:

Adding the portlet to the page should now render our portlet correctly:

Conclusion

We’ve now got a Vaadin application project with a Vaadin add-on that will run both as a webapp for ease of development and as a portlet in Liferay.

References