This website uses cookies to ensure you get the best experience. Learn More.
Pushing Using Vaadin, Websockets and Liferay 6
In Vaadin 7.2, server push support was introduced but only for servlet deployments. The initial plan was to add support for portlets "right after that release". That's not exactly what happened but for the upcoming Vaadin 7.6, there has been some changes which makes it easier to support push in a portal environment.
Portals bring some extra challenges for server push, mainly because you only have access to shared portal requests in a portal environment and not necessarily to the low level HTTP request. Some requests in a portal, such as resource requests, are delivered only to one portlet and could theoretically be used for a push connection. The portlet 2.0 specification (JSR-286) however does not mention anything about asynchronous processing, leaving requests open for a long time or upgrading resource requests to websocket connections. Quite understandable as the portlet 2.0 specification was finalized in 2008, before the Servlet 3.0 spec (2009) and the Websockets spec (2013).
What Liferay and other portals offer is the possibility to deploy servlets along with portlets, so that all servlets and portlets are part of the same web application (WAR file). We can therefore use a portlet to serve the UI and all related parts, and a separate servlet for the push channel. For this approach to work we must ensure three things:
the same session must be accessible from both the servlet and the portlet
the same VaadinSession and UI instances must be used by both the servlet and the portlet
push requests must be sent through the servlet and not the portlet
Vaadin 7.6 solves the first problem by storing the VaadinSession object in the session using application scope, which makes it available for all servlets and portlets in the same war file.
The last two steps you can implement using a custom VaadinServlet and VaadinService. This has already been done in the Portal Push add-on, so let's see how that can be used.
1. Start by creating a Liferay project using the vaadin liferay archetype
mvn archetype:generate -DarchetypeRepository=https://maven.vaadin.com/vaadin-prereleases -DarchetypeGroupId=com.vaadin -DarchetypeArtifactId=vaadin-archetype-liferay-portlet -DarchetypeVersion=7.6.0.beta2 -DgroupId=com.example.portalpush -DartifactId=portal-push-liferay-example -Dversion=1.0-SNAPSHOT
2. Configure a Liferay profile in Maven
See https://vaadin.com/book/-/page/portal.liferay.html. Alternatively, define the parameters for the liferay-maven-plugin in pom.xml
3. Add the Vaadin pre-release repository in <repositories> and <pluginRepositories>. This is only needed as we are using a beta version of Vaadin 7.6.
<repositories>
…
<repository>
<id>vaadin-pre-releases</id>
<url>https://maven.vaadin.com/vaadin-prereleases</url>
</repository>
</repositories>
<pluginRepositories>
...
<pluginRepository>
</pluginRepository>
</pluginRepositories>
4. Add the portal push add-on
<dependency>
<groupId>org.vaadin.artur</groupId>
<artifactId>portal-push</artifactId>
<version>0.2.0</version>
</dependency>
5. Change web.xml and portlet.xml to use the servlet and portlet class from the add-on
./src/main/webapp/WEB-INF/web.xml:
<servlet-class>org.vaadin.artur.portalpush.PushServlet</servlet-class>
./src/main/webapp/WEB-INF/portlet.xml:
<portlet-class>org.vaadin.artur.portalpush.PushPortlet</portlet-class>
6. Edit the UI class and add @Push and something which pushes
@Push(transport=Transport.WEBSOCKET_XHR)
private ScheduledExecutorService service = Executors.newScheduledThreadPool(1);
service.scheduleWithFixedDelay(new Runnable() { // Run every second
@Override
public void run() {
access(new Runnable() {// Synchronize with Vaadin
layout.addComponent(new Label(
"Server time is now: " + new Date()));
}
});
}, 1, 1, TimeUnit.SECONDS);
7. Build and deploy the portlet
mvn install liferay:deploy
There is a full working example project available at https://github.com/Artur-/portal-push-liferay-example. Always remember to use UI.access from non-request threads to avoid synchronization problems and race conditions.
This approach to push requires the portal to support deploying Servlet 3.0 servlets. Unfortunately Liferay 6 supports only 2.4 and will automatically add a servlet-filter in front of the servlet, which breaks the required async support. Because of this, websockets will work in Liferay 6 using this approach, but long polling will not work.
Session timeout in portals is based on HTTP requests, so if you are using websockets for all communications, you can possibly get session timeouts even though the user is using the portlet. The simplest way to get around this is to use the WEBSOCKET_XHR transport so that all server requests are sent as HTTP requests and session extension will work in the same way as when not using push.
Tomcat 7 is not capable of sharing the HTTP session between websockets and the servlet. This sometimes have strange implications, upgrade to Tomcat 8 to avoid problems.
If you experience problems, please refer to http://vaadin.com/wiki/-/wiki/Main/Configuring+push+for+your+environment or create an issue at https://github.com/Artur-/portal-push/issues