Contexts and Dependency Injection for JSF Portlets

In December 2009, JSR 299 introduced the Contexts and Dependency Injection (CDI) 1.0 standard into the Java EE 6 platform. In April 2013, JSR 346 updated CDI to version 1.1 for Java EE 7. In addition, JSR 344, the JSF 2.2 specification which is another component of Java EE 7, introduced a dependency on the CDI API for the javax.faces.view.ViewScoped annotation and for the Faces Flows feature. JBoss Weld is the Reference Implementation (RI) for CDI, and Apache OpenWebBeans is another open source implementation.

Still wondering what CDI accomplishes? Visit the CDI Specs to learn more about CDI and why it has become a popular component for JSF.

This tutorial covers the following topics:

  • Configuring JSF Portlets to Use CDI
  • Configuring the Liferay CDI Portlet Bridge
  • Understanding CDI in JSF Annotations

First, you’ll configure your portlets to use a CDI implementation, such as JBoss Weld or CanDI.

Configuring JSF Portlets to Use CDI

Several app-server/portal/CDI-implementation combinations support using CDI with JSF on Liferay Portal.

For Liferay Portal 6.2, you can use one of these combinations:

For Liferay Portal 6.1, you can use one of these combinations:

When developing portlets with CDI 1.0, you must include a WEB-INF/beans.xml descriptor in your JSF portlet plugin’s .war deployment, so that when the CDI implementation scans the classpath it detects the CDI-related annotations of your classes.

Here’s an example WEB-INF/beans.xml descriptor for a portlet plugin:

<beans xmlns="http://java.sun.com/xml/ns/javaee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
    http://java.sun.com/xml/ns/javaee/beans_1_0.xsd">
</beans>

If you’re deploying your portlet on JBoss AS 7, you must also include a WEB-INF/jboss-deployment-structure.xml descriptor in your portlet plugin’s .war deployment to include the CDI-related modules. Here’s an example of a portlet’s WEB-INF/jboss-deployment-structure.xml descriptor for JBoss:

<?xml version="1.0"?>
<jboss-deployment-structure xmlns="urn:jboss:deployment-structure:1.0">
    <deployment>
        <exclusions>
            <module name="javaee.api" />
            <module name="org.apache.log4j" />
        </exclusions>
        <dependencies>
            <module name="com.liferay.portal" />
            <module name="javax.annotation.api" />
            <module name="javax.enterprise.api" />
            <module name="javax.inject.api" />
            <module name="javax.interceptor.api" />
            <module name="javax.validation.api" />
            <module name="javax.mail.api" />
            <module name="org.jboss.modules" />
        </dependencies>
    </deployment>
</jboss-deployment-structure>

For a portlet to use Weld on most app servers (excluding Resin), the portlet’s WEB-INF/web.xml descriptor must include the following filter and filter mapping:

<filter>    
    <filter-name>WeldCrossContextFilter</filter-name>    
    <filter-class>org.jboss.weld.servlet.WeldCrossContextFilter</filter-class>
</filter>
<filter-mapping>    
    <filter-name>WeldCrossContextFilter</filter-name>    
    <url-pattern>/*</url-pattern>    
    <dispatcher>INCLUDE</dispatcher>    
    <dispatcher>FORWARD</dispatcher>    
    <dispatcher>ERROR</dispatcher>
</filter-mapping>

Portlets on Resin can use the CanDI implementation of CDI, which Resin includes by default.

If you’re running on Tomcat and you choose not to include Weld in Tomcat’s global classpath, then you must include it in the portlet’s classpath by adding it to the portlet’s WEB-INF/lib folder.

If you’re on Tomcat and you’re using a Maven project for your portlet plugin, you must specify the Weld servlet as a dependency. Here’s an excerpt from a Maven POM file that exemplifies specifying the Weld servlet dependency:

<dependency>    
    <groupId>org.jboss.weld.servlet</groupId>    
    <artifactId>weld-servlet</artifactId>    
    <version>1.1.10.Final</version>
</dependency>

If you’re on Tomcat you must also add a Weld servlet listener in your portlet’s WEB-INF/web.xml file:

<listener>    
    <listener-class>org.jboss.weld.environment.servlet.Listener</listener-class>
</listener>

Next, you’ll learn how to configure the Liferay CDI Portlet Bridge

Configuring the Liferay CDI Portlet Bridge

The Liferay CDI Portlet Bridge makes it possible to use CDI with your JSF portlets on Liferay. Your JSF portlet projects must include the Liferay CDI Portlet Bridge as a dependency.

For example, to specify the bridge dependency in a Maven project for Liferay 6.2, add to your POM’s dependencies element a dependency like the following one:

<dependency>    
    <groupId>com.liferay.cdi</groupId>    
    <artifactId>cdi-portlet-bridge-shared</artifactId>    
    <version>6.2.0.2</version>
</dependency>

The WEB-INF/portlet.xml descriptor of the portlet must include the following markup:

<filter>    
    <filter-name>CDIPortletFilter</filter-name>    
    <filter-class>com.liferay.cdi.portlet.bridge.CDIPortletFilter</filter-class>
    <lifecycle>ACTION_PHASE</lifecycle>
    <lifecycle>EVENT_PHASE</lifecycle>
    <lifecycle>RENDER_PHASE</lifecycle>
    <lifecycle>RESOURCE_PHASE</lifecycle>
</filter>
<filter-mapping>
    <filter-name>CDIPortletFilter</filter-name>    
    <portlet-name>my-portlet-name</portlet-name>
</filter-mapping>

Additionally, the portlet’s WEB-INF/web.xml descriptor must include the following declarations:

<filter>
    <filter-name>CDICrossContextFilter</filter-name>
    <filter-class>com.liferay.cdi.portlet.bridge.CDICrossContextFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>CDICrossContextFilter</filter-name>
    <url-pattern>/*</url-pattern>
    <dispatcher>INCLUDE</dispatcher>
    <dispatcher>FORWARD</dispatcher>
    <dispatcher>ERROR</dispatcher>
</filter-mapping>
<listener>
    <listener-class>com.liferay.cdi.portlet.bridge.CDIContextListener</listener-class>
</listener>

You’ve completed configuring the Liferay CDI Portlet Bridge for you JSF portlet. Now that everything is configured, you are ready to begin development with CDI.

Understanding CDI in JSF Annotations

When developing portlets with CDI, you can annotate Java classes as CDI managed beans using @Named with the following scopes:

CDI Annotation Description
@ApplicationScoped An @ApplicationScoped managed bean exists for the entire lifetime of the portlet application.
@ConversationScoped A @ConversationScoped managed bean is created when Conversation.begin() is called and is scheduled for garbage collection when Conversation.end() is called.
@FlowScoped A @FlowScoped managed bean is created when a JSF 2.2 Flow begins and scheduled for garbage collection when a JSF 2.2 Flow completes.
@RequestScoped A @RequestScoped managed bean exists during an ActionRequest, RenderRequest, or ResourceRequest. Beans that are created during the ActionRequest do not survive into the RenderRequest.
@SessionScoped A @SessionScoped managed bean exists for the duration of the user session.

In addition to CDI scope annotations, it’s important to understand JSF 2 annotations and their equivalence to CDI annotations.

JSF Annotation Equivalent CDI Annotation
javax.faces.ManagedBean javax.inject.Named
javax.faces.ApplicationScoped javax.enterprise.context.ApplicationScoped
javax.faces.RequestScoped No such equivalent, since javax.enterprise.context.RequestScoped does not span portlet lifecycle phases.
javax.faces.SessionScoped javax.enterprise.context.SessionScoped
javax.faces.ManagedProperty (corresponding setter method required) javax.inject.Inject (corresponding setter method not required)

This should help with your understanding of CDI and JSF annotations. And as you’ve also seen in this tutorial, configuring CDI for your JSF portlets and configuring the Liferay CDI Portlet Bridge is a snap!

Related Topics

Understanding Liferay Faces Bridge

Communicating Between JSF Portlets Using IPC

Understanding Liferay Faces Portal

Understanding Liferay Faces Alloy

0 (0 Votes)
Communicating Between JSF Portlets Using IPC Previous