Portlet Development using JSF, PrimeFaces and Spring

About the Post:

This article presents techniques on how to develop Java Portlets using JavaServer Faces, PrimeFaces and Spring. This hands-on example will integrate all of these technologies into a single application.

Assumptions

This post assumes that you have a basic understanding of Portlet, JSF, PrimeFaces and Spring. And a good understanding of Java 5 and annotations.

Resources

Before getting started, please have the following downloaded and setup in your environment.

Development Steps

  • Create a Web Project named SimplePortlet and convert it to Maven Project / enable Maven support.
  • Let’s start with the application requirements. So, build your Maven Configurations – pom.xml file. As you might have guessed, this will contain the dependencies for the following. If you have confusion about any of the dependencies below, don’t worry, things will be clear as we move forward.
    • Spring Web
    • <!-- Spring Web -->
      <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-web</artifactId>
      <version>${spring.version}</version>
      </dependency>
    • Portlet
    • <!-- Portlet -->
      <dependency>
      <groupId>javax.portlet</groupId>
      <artifactId>portlet-api</artifactId>
      <version>${portlet-api.version}</version>
      <scope>provided</scope><!-- Prevents addition to war file -->
      </dependency>
    • Servlet
    • <!-- Servlet -->
      <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>servlet-api</artifactId>
      <version>${servlet-api.version}</version>
      <scope>provided</scope><!-- Prevents addition to war file -->
      </dependency>
      <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>jstl</artifactId>
      <version>1.2</version>
      <scope>compile</scope>
      </dependency>
    • JEE Dependency Injection
    • <dependency>
      <groupId>javax.inject</groupId>
      <artifactId>javax.inject</artifactId>
      <version>1</version>
      </dependency>
    • JSF
    • <!-- JSF -->
      <dependency>
      <groupId>com.sun.faces</groupId>
      <artifactId>jsf-api</artifactId>
      <version>2.1.6</version>
      </dependency>
      <dependency>
      <groupId>com.sun.faces</groupId>
      <artifactId>jsf-impl</artifactId>
      <version>2.1.6</version>
      </dependency>
    • EL
    •  <!-- EL -->
      <dependency>
      <groupId>com.sun.el</groupId>
      <artifactId>el-ri</artifactId>
      <version>1.0</version>
      </dependency>
      <dependency>
      <groupId>javax.el</groupId>
      <artifactId>el-api</artifactId>
      <version>1.0</version>
      <scope>provided</scope>
      </dependency>
    • PrimeFaces
    • <!-- PrimeFaces -->
      <dependency>
      <groupId>org.primefaces</groupId>
      <artifactId>primefaces</artifactId>
      <version>3.0</version>
      </dependency>
    • PortletFaces bridge
    • <!-- PortletFaces Bridge -->
      <dependency>
      <groupId>org.portletfaces</groupId>
      <artifactId>portletfaces-bridge</artifactId>
      <version>2.0.1</version>
      </dependency>
      <dependency>
      <groupId>org.portletfaces.alloy.faces</groupId>
      <artifactId>alloyfaces</artifactId>
      <version>1.0.1.1</version>
      </dependency>
      <!-- BEGIN: Required for bridge:inputFile -->
      <dependency>
      <groupId>commons-fileupload</groupId>
      <artifactId>commons-fileupload</artifactId>
      <version>1.2.2</version>
      </dependency>
      <dependency>
      <groupId>commons-io</groupId>
      <artifactId>commons-io</artifactId>
      <version>1.3.1</version>
      </dependency>
      <!-- END: Required for bridge:inputFile -->.

    Add the following repositories to your pom.xml so that all the dependencies can be downloaded successfully.

      <!-- Repositories -->
      <repositories>
      <repository>
      <id>maven2-repository.dev.java.net</id>
      <url>http://download.java.net/maven/2</url>
      </repository>
      <repository>
      <id>maven2-repository.jboss.org</id>
      <url>http://repository.jboss.org/nexus/content/groups/public-jboss</url>
      </repository>
      <repository>
      <id>maven2-repository-portletfaces.org</id>
      <url>http://repository.portletfaces.org/content/repositories/portletfaces-releases</url>
      </repository>
      <repository>
      <id>prime-repo</id>
      <name>PrimeFaces Maven Repository</name>
      <url>http://repository.primefaces.org</url>
      <layout>default</layout>
      </repository>
      </repositories>
  • Add the the following properties to your pom.xml file.
  • <properties>
    <pluto.version>2.0.3</pluto.version>
    <portlet-api.version>2.0</portlet-api.version>
    <servlet-api.version>2.5</servlet-api.version>
    <jsp-api.version>2.0</jsp-api.version>
    <junit.version>4.10</junit.version>
    <spring.version>3.1.1.RELEASE</spring.version>
    </properties>
  • Build your web.xml file
    • Add Spring bootstrap – ContextLoaderListener.
    • Add RequestContextListener to the web.xml to enable Spring support request and session scoped beans.
    • Add JSF Servlet Configurations.
    • Finally, the web.xml looks like this:
    • <?xml version="1.0" encoding="UTF-8"?>
      <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
       xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
       id="WebApp_ID" version="3.0">
       <display-name>SimplePortlet</display-name>
       <context-param>
       <param-name>contextConfigLocation</param-name>
       <param-value>classpath:applicationContext.xml</param-value>
       </context-param>
       <context-param>
       <param-name>javax.faces.CONFIG_FILES</param-name>
       <param-value>/WEB-INF/faces-config.xml</param-value>
       </context-param>
       <context-param>
       <param-name>javax.faces.PROJECT_STAGE</param-name>
       <param-value>Development</param-value>
       </context-param>
       <context-param>
       <param-name>javax.faces.PARTIAL_STATE_SAVING</param-name>
       <param-value>false</param-value>
       </context-param>
       <listener>
       <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
       </listener>
       <listener>
       <listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
       </listener>
       <servlet>
       <servlet-name>Faces Servlet</servlet-name>
       <servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
       <load-on-startup>1</load-on-startup>
       </servlet>
       <!-- Prevent direct access to Facelet view XHTML by the userAgent (browser). -->
       <security-constraint>
       <web-resource-collection>
       <web-resource-name>Facelet View XHTML</web-resource-name>
       <url-pattern>*.xhtml</url-pattern>
       </web-resource-collection>
       <auth-constraint>
       <role-name>nobody</role-name>
       </auth-constraint>
       </security-constraint>
       <security-role>
       <role-name>nobody</role-name>
       </security-role>
      </web-app>
  • Create faces-config.xml file and add SpringBeanFacesELResolver into it. JSF Els look up Spring beans with the help of this EL Resolver. This looks like:
    <?xml version="1.0" encoding="UTF-8"?>
    <faces-config version="2.0" xmlns="http://java.sun.com/xml/ns/javaee"
    xmlns:xi="http://www.w3.org/2001/XInclude" 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/web-facesconfig_2_0.xsd">
    <application>
    <el-resolver>org.springframework.web.jsf.el.SpringBeanFacesELResolver</el-resolver>
    </application>
    </faces-config>
  • Write your JSF Controller class. In this example, I’ve created a controller class that has a zipCode field which is submitted from the user request. This controller has dependency with the service layer to get the weather information which has been injected into this. Controller invokes the service class, WeatherServiceClient in this case, to get weather info for that zip code and gets it back as a WeatherReturn. (The controller also has a field called currentTime. The view invokes this using AJAX and displays the current time. This is done using PrimeFaces poll component)
    /**
     *
     */
    package com.sourceallies.portlets.spring.controller;
     
    import java.io.Serializable;
    import java.text.DateFormat;
    import java.text.SimpleDateFormat;
    import java.util.Date;
    import java.util.logging.Logger;
     
    import javax.inject.Inject;
    import javax.inject.Named;
     
    import com.sourceallies.portlets.spring.bean.WeatherReturn;
    import com.sourceallies.service.WeatherServiceClient;
     
    /**
     * @author lsah
     *
     */
    @Named("viewController")
    public class WeatherViewController implements Serializable {
     
     /**
     *
     */
     private static final long serialVersionUID = 8811407513884269900L;
     
     private static final Logger LOGGER = Logger.getLogger(WeatherViewController.class.getName());
     
     private static final DateFormat DATE_FORMAT = new SimpleDateFormat("MM/dd/yyyy hh:mm:ss a z");
     
     @Inject
     @Named("weatherServiceClient")
     private WeatherServiceClient weatherServiceClient;
     
     private WeatherReturn weatherReturn;
     
     private String zipCode = "50312";
     
     private String currentTime = DATE_FORMAT.format(new Date());
     
     /**
     * @return the currentTime
     */
     public String getCurrentTime() {
     return currentTime;
     }
     
     /**
     * @param currentTime
     *            the currentTime to set
     */
     public void setCurrentTime(String currentTime) {
     this.currentTime = currentTime;
     }
     
     public WeatherViewController() {
     }
     
     public String updateWeather() {
     LOGGER.info("Zip Code: " + zipCode);
     weatherReturn = weatherServiceClient.getWeatherByZipCode(zipCode);
     return null;
     }
     
     public void updateTime() {
     // LOGGER.info("------------------>>>>>>Updating time...");
     this.currentTime = DATE_FORMAT.format(new Date());
     }
     
     /**
     * @return the weatherServiceClient
     */
     public WeatherServiceClient getWeatherServiceClient() {
     return weatherServiceClient;
     }
     
     /**
     * @param weatherServiceClient
     *            the weatherServiceClient to set
     */
     public void setWeatherServiceClient(WeatherServiceClient weatherServiceClient) {
     this.weatherServiceClient = weatherServiceClient;
     }
     
     /**
     * @return the weatherReturn
     */
     public WeatherReturn getWeatherReturn() {
     if (this.weatherReturn == null) {
     weatherReturn = weatherServiceClient.getWeatherByZipCode("50312");
     LOGGER.info("Temperature (Spring Portlet MVC): " + weatherReturn.getTemperature());
     }
     return weatherReturn;
     }
     
     /**
     * @param weatherReturn
     *            the weatherReturn to set
     */
     public void setWeatherReturn(WeatherReturn weatherReturn) {
     this.weatherReturn = weatherReturn;
     }
     
     /**
     * @return the zipCode
     */
     public String getZipCode() {
     return zipCode;
     }
     
     /**
     * @param zipCode
     *            the zipCode to set
     */
     public void setZipCode(String zipCode) {
     this.zipCode = zipCode;
     }
    }
  • The WeatherReturn bean is shown below.
  • /**
    * Weather.java
    * Feb 28, 2012
    */
    package com.sourceallies.portlets.spring.bean;
     
    import java.io.Serializable;
     
    /**
    * @author Lal
    *
    */
    public class WeatherReturn implements Serializable {
     
    /**
    *
    */
    private static final long serialVersionUID = 2221936547464343855L;
     
    private String zipCode;
     
    private String temperature;
     
    private String city;
     
    private String state;
     
    private String description;
     
    /**
    * @return the zipCode
    */
    public String getZipCode() {
    return zipCode;
    }
     
    /**
    * @param zipCode
    *            the zipCode to set
    */
    public void setZipCode(String zipCode) {
    this.zipCode = zipCode;
    }
     
    /**
    * @return the temperature
    */
    public String getTemperature() {
    return temperature;
    }
     
    /**
    * @param temperature
    *            the temperature to set
    */
    public void setTemperature(String temperature) {
    this.temperature = temperature;
    }
     
    /**
    * @return the city
    */
    public String getCity() {
    return city;
    }
     
    /**
    * @param city
    *            the city to set
    */
    public void setCity(String city) {
    this.city = city;
    }
     
    /**
    * @return the state
    */
    public String getState() {
    return state;
    }
     
    /**
    * @param state
    *            the state to set
    */
    public void setState(String state) {
    this.state = state;
    }
     
    /**
    * @return the description
    */
    public String getDescription() {
    return description;
    }
     
    /**
    * @param description
    *            the description to set
    */
    public void setDescription(String description) {
    this.description = description;
    }
     
    /**
    * @param zipCode
    * @return
    */
    public WeatherReturn withZipCode(String zipCode) {
    this.zipCode = zipCode;
    return this;
    }
     
    /**
    * @param temperature
    * @return
    */
    public WeatherReturn withTemperature(String temperature) {
    this.temperature = temperature;
    return this;
    }
     
    /**
    * @param city
    * @return
    */
    public WeatherReturn withCity(String city) {
    this.city = city;
    return this;
    }
     
    /**
    * @param state
    * @return
    */
    public WeatherReturn withState(String state) {
    this.state = state;
    return this;
    }
     
    /**
    * @param description
    * @return
    */
    public WeatherReturn withDescription(String description) {
    this.description = description;
    return this;
    }
    }
  • Write your service layer. I’ve simply short-circuited the service layer for example purpose ONLY. WeatherServiceClient in this case simply returns an object with static / hard-coded values as shown below. A real-time service client would invoke a real-time weather web service and get the data from there – which is beyond the scope of this article.
  • /**
    *
    */
    package com.sourceallies.service;
     
    import java.util.logging.Logger;
     
    import javax.inject.Named;
     
    import com.sourceallies.portlets.spring.bean.WeatherReturn;
     
    /**
    * @author lsah
    *
    */
    @Named(value = "weatherServiceClient")
    public class WeatherServiceClient {
     
    private static final Logger LOGGER = Logger.getLogger(WeatherServiceClient.class.getName());
     
    public WeatherServiceClient() {
    }
     
    /**
    * @param zipCode
    * @return the weather for the given zip code.
    */
    public WeatherReturn getWeatherByZipCode(String zipCode) {
    LOGGER.info("Zip Code: " + zipCode);
     
    // Invoke Web Service / DAO layer to get the real-time data and return
     
    return new WeatherReturn().withZipCode(zipCode).withCity("Des Moines").withState("IA").withTemperature("37").withDescription("Light Rain");
    }
    }
  • This WeatherServiceClient mentioned above is named as “weatherServiceClient”. This was injected into the controller class using @Inject and @Named annotations.
  • Write your Spring Bean configuration file. I’ve named it applicationContext.xml in the web.xml contextConfigLocation context parameter. You can choose any name as long as you have the same name in the web.xml above. We have all the beans configured using annotations so this file doesn’t have any bean creation setup. Instead it tells Spring the meta information about the annotation processing i.e. enable annotation processing and the packages that contain the annotated beans to be processed via annotation processing.
  • <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd">
     
    <context:annotation-config />
    <context:component-scan base-package="com.sourceallies.portlets.spring.controller" />
    <context:component-scan base-package="com.sourceallies.service" />
    </beans>
  • Now let’s create the views. As you might have guessed, we are going to use Facelets on views. Since a Portlet operates in three modes namely VIEW, EDIT and HELP and we are going to create a portlet to support all three modes, we will create three view pages naming them view.xhtml, edit.xhtml and help.xhtml. Create a folder named xhtmls inside WEB-INF to place these files. Let’s start with view.xhtml.
    • This contains a JSF form with a singular field zipCode. This portlet will query weather for the entered zip code. It displays the weather info in the same page. Even though, you can navigate to any view page using JSF navigation based on your need. Here’s our view.
    • <ui:composition xmlns="http://www.w3.org/1999/xhtml"
      xmlns:f="http://java.sun.com/jsf/core"
      xmlns:h="http://java.sun.com/jsf/html"
      xmlns:ui="http://java.sun.com/jsf/facelets"
      xmlns:p="http://primefaces.org/ui">
      <h:head />
      <h:form>
      <h4>
      <h:outputText value="Time: #{viewController.currentTime}"
      id="currentTime" />
      <p:poll interval="1" listener="#{viewController.updateTime()}"
      update="currentTime" />
      </h4>
      <h3>Check Weather</h3>
      Please enter your Zip Code below to view weather update: <br />
      <br />
      Zip Code: <h:inputText value="#{viewController.zipCode}" />
      <h:commandButton action="#{viewController.updateWeather()}"
      value="Submit" />
      <h3>Weather at Zip Code: #{viewController.zipCode}</h3>
      <i>Location: </i>
      <h:outputText
      value="#{viewController.weatherReturn.city}, #{viewController.weatherReturn.state}"
      id="citystate" />
      <br />
      <i>Temperature: </i>
      <h:outputText value="#{viewController.weatherReturn.temperature} °F"
      id="temperature" />
      <br />
      <i>Description: </i>
      <h:outputText value="#{viewController.weatherReturn.description}"
      id="desc" />
      <br />
      </h:form>
      </ui:composition>
    • I created the exact same page for EDIT mode just to have EDIT mode support – just copy and paste the same content in a file named edit.xhtml. However, you can create your own based on what you need for your application.
    • I’ve created a simplest page for HELP mode for this example.
    • <?xml version="1.0" encoding="UTF-8"?>
      <ui:composition xmlns:f="http://java.sun.com/jsf/core"
      xmlns:h="http://java.sun.com/jsf/html"
      xmlns:ui="http://java.sun.com/jsf/facelets">
      HELP MODE
      </ui:composition>
  • Now that we have created almost everything, let’s create the Portlet configuration file / deployment descriptor. As mentioned before, we are using PortletFaces bridge. So, we are going to use org.portletfaces.bridge.GenericFacesPortlet as our portlet class, the class provided by PortletFaces library to handle portlet lifecycles. This class along with the PortletFaces library is responsible for bridging the gap between portlet and JSF servlet lifecycles and handles JSF views as portlets on the Portal page. Here is the Portlet configurations file:
  • <?xml version="1.0" encoding="UTF-8"?>
    <portlet-app xmlns="http://java.sun.com/xml/ns/portlet/portlet-app_1_0.xsd"
    version="1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/portlet/portlet-app_1_0.xsd
    http://java.sun.com/xml/ns/portlet/portlet-app_1_0.xsd">
    <!-- JSF PortletFaces Bridge -->
    <portlet>
    <description>Weather Portlet JSF PortletFaces Bridge</description>
    <portlet-name>weatherPortlet</portlet-name>
    <display-name>Weather Portlet using JSF PortletFaces Bridge</display-name>
    <portlet-class>org.portletfaces.bridge.GenericFacesPortlet</portlet-class>
    <init-param>
    <name>javax.portlet.faces.defaultViewId.view</name>
    <value>/WEB-INF/xhtmls/view.xhtml</value>
    </init-param>
    <init-param>
    <name>javax.portlet.faces.defaultViewId.edit</name>
    <value>/WEB-INF/xhtmls/edit.xhtml</value>
    </init-param>
    <init-param>
    <name>javax.portlet.faces.defaultViewId.help</name>
    <value>/WEB-INF/xhtmls/help.xhtml</value>
    </init-param>
    <supports>
    <mime-type>text/html</mime-type>
    <portlet-mode>VIEW</portlet-mode>
    <portlet-mode>HELP</portlet-mode>
    <portlet-mode>EDIT</portlet-mode>
    </supports>
    <supported-locale>en</supported-locale>
    <portlet-info>
    <title>Weather Portlet (PortletFaces) Title</title>
    <short-title>WeatherPortletPortletFacesTitle</short-title>
    <keywords>weather portlet faces portlet</keywords>
    </portlet-info>
    </portlet>
    </portlet-app>
  • Here is the snapshot of my Eclipse project assembly.
SimplePortlet Project Assembly

SimplePortlet Project Assembly

  • This completes our development of sample Weather portlet. Now let’s deploy this portlet.

Deployment

Now that we are done with the development, let’s deploy this portlet on Apache Pluto Portal Server. I am using Pluto 2.0.3.

  • Create Tomcat Context Deployment Descriptor. This is an XML file named same as the project name and is placed in the webapp/META-INF/ directory. Our SimplePortlet.xml contains the following information:
  • <?xml version="1.0" encoding="UTF-8"?>
    <Context path="/SimplePortlet" docBase="SimplePortlet" crossContext="true" />
  • Add the following plugins to yout pom.xml. The first is the compiler plugin that tells maven which version of java to use for compile java classes. The second and third are maven war and pluto plugins which tell maven how to create WAR assembly and where to put the deployment descriptors in the assembly so that Pluto can locate the deployment configurations and deploy the portlet. The fourth and last one is the automatic deployment plugin that tells maven where to copy the final deployment package. We are copying to pluto webapps directory so that it will be automatically deployed.
  • <build>
    <finalName>${pom.name}</finalName>
    <plugins>
    <!-- configure to use Java 6 to compile (change to your JDK) -->
    <plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-compiler-plugin</artifactId>
    <configuration>
    <source>1.6</source>
    <target>1.6</target>
    </configuration>
    </plugin><!-- configure maven-war-plugin to use updated web.xml -->
    <plugin>
    <artifactId>maven-war-plugin</artifactId>
    <configuration>
    <webXml>${project.build.directory}/pluto-resources/web.xml</webXml>
    </configuration>
    </plugin>
    <!-- bind 'pluto2:assemble' goal to 'generate-resources' lifecycle -->
    <plugin>
    <groupId>org.apache.portals.pluto</groupId>
    <artifactId>maven-pluto-plugin</artifactId>
    <version>${pluto.version}</version>
    <executions>
    <execution>
    <phase>generate-resources</phase>
    <goals>
    <goal>assemble</goal>
    </goals>
    </execution>
    </executions>
    </plugin>
    <plugin>
    <artifactId>maven-antrun-plugin</artifactId>
    <executions>
    <execution>
    <phase>integration-test</phase>
    <configuration>
    <tasks>
    <property environment="env" />
    <!-- This assumes that you have set a CATALINA_HOME environmental
    variable -->
    <property name="pluto.home" value="${catalina.home}" />
    <copy file="target/${pom.name}.war" todir="${pluto.home}/webapps" />
    </tasks>
    </configuration>
    <goals>
    <goal>run</goal>
    </goals>
    </execution>
    </executions>
    </plugin>
    </plugins>
    </build>
  • Add a property catalina.home to your pom.xml file. Change its value to point to the home directory of your Pluto installation directory.
  • <catalina.home>/home/lsah/java/pluto-2.0.3</catalina.home>
  • The resulting pom.xml looks like this.
  • <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>com.sourceallies.simpleportlet</groupId>
    <artifactId>SimplePortlet</artifactId>
    <version>0.1</version>
    <packaging>war</packaging>
    <name>${pom.artifactId}</name>
    <!-- Dependency Version Properties ======================================= -->
    <properties>
    <pluto.version>2.0.3</pluto.version>
    <portlet-api.version>2.0</portlet-api.version>
    <servlet-api.version>2.5</servlet-api.version>
    <jsp-api.version>2.0</jsp-api.version>
    <junit.version>4.10</junit.version>
    <spring.version>3.1.1.RELEASE</spring.version>
    <catalina.home>/home/lsah/java/pluto-2.0.3</catalina.home>
    </properties>
    <dependencies>
    <!-- Spring Web -->
    <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-web</artifactId>
    <version>${spring.version}</version>
    </dependency>
     
    <!-- Portlet -->
    <dependency>
    <groupId>javax.portlet</groupId>
    <artifactId>portlet-api</artifactId>
    <version>${portlet-api.version}</version>
    <scope>provided</scope><!-- Prevents addition to war file -->
    </dependency>
     
    <!-- Servlet -->
    <dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>servlet-api</artifactId>
    <version>${servlet-api.version}</version>
    <scope>provided</scope><!-- Prevents addition to war file -->
    </dependency>
    <dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>jstl</artifactId>
    <version>1.2</version>
    <scope>compile</scope>
    </dependency>
     
    <!-- JEE Dependency Injection -->
    <dependency>
    <groupId>javax.inject</groupId>
    <artifactId>javax.inject</artifactId>
    <version>1</version>
    </dependency>
     
    <!-- JSF -->
    <dependency>
    <groupId>com.sun.faces</groupId>
    <artifactId>jsf-api</artifactId>
    <version>2.1.6</version>
    </dependency>
    <dependency>
    <groupId>com.sun.faces</groupId>
    <artifactId>jsf-impl</artifactId>
    <version>2.1.6</version>
    </dependency>
     
    <!-- EL -->
    <dependency>
    <groupId>com.sun.el</groupId>
    <artifactId>el-ri</artifactId>
    <version>1.0</version>
    </dependency>
    <dependency>
    <groupId>javax.el</groupId>
    <artifactId>el-api</artifactId>
    <version>1.0</version>
    <scope>provided</scope>
    </dependency>
     
    <!-- PrimeFaces -->
    <dependency>
    <groupId>org.primefaces</groupId>
    <artifactId>primefaces</artifactId>
    <version>3.0</version>
    </dependency>
     
    <!-- PortletFaces Bridge -->
    <dependency>
    <groupId>org.portletfaces</groupId>
    <artifactId>portletfaces-bridge</artifactId>
    <version>2.0.1</version>
    </dependency>
    <dependency>
    <groupId>org.portletfaces.alloy.faces</groupId>
    <artifactId>alloyfaces</artifactId>
    <version>1.0.1.1</version>
    </dependency>
    <!-- BEGIN: Required for bridge:inputFile -->
    <dependency>
    <groupId>commons-fileupload</groupId>
    <artifactId>commons-fileupload</artifactId>
    <version>1.2.2</version>
    </dependency>
    <dependency>
    <groupId>commons-io</groupId>
    <artifactId>commons-io</artifactId>
    <version>1.3.1</version>
    </dependency>
    <!-- END: Required for bridge:inputFile -->
     
    <!-- JUnit -->
    <dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>${junit.version}</version>
    <scope>test</scope>
    </dependency>
    </dependencies>
    <build>
    <finalName>${pom.name}</finalName>
    <plugins>
    <!-- configure to use Java 6 to compile (change to your JDK) -->
    <plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-compiler-plugin</artifactId>
    <configuration>
    <source>1.6</source>
    <target>1.6</target>
    </configuration>
    </plugin><!-- configure maven-war-plugin to use updated web.xml -->
    <plugin>
    <artifactId>maven-war-plugin</artifactId>
    <configuration>
    <webXml>${project.build.directory}/pluto-resources/web.xml</webXml>
    </configuration>
    </plugin>
    <!-- bind 'pluto2:assemble' goal to 'generate-resources' lifecycle -->
    <plugin>
    <groupId>org.apache.portals.pluto</groupId>
    <artifactId>maven-pluto-plugin</artifactId>
    <version>${pluto.version}</version>
    <executions>
    <execution>
    <phase>generate-resources</phase>
    <goals>
    <goal>assemble</goal>
    </goals>
    </execution>
    </executions>
    </plugin>
    <plugin>
    <artifactId>maven-antrun-plugin</artifactId>
    <executions>
    <execution>
    <phase>integration-test</phase>
    <configuration>
    <tasks>
    <property environment="env" />
    <!-- This assumes that you have set a CATALINA_HOME environmental
    variable -->
    <property name="pluto.home" value="${catalina.home}" />
    <copy file="target/${pom.name}.war" todir="${pluto.home}/webapps" />
    </tasks>
    </configuration>
    <goals>
    <goal>run</goal>
    </goals>
    </execution>
    </executions>
    </plugin>
    </plugins>
    <pluginManagement>
    <plugins>
    <!--This plugin's configuration is used to store Eclipse m2e settings
    only. It has no influence on the Maven build itself. -->
    <plugin>
    <groupId>org.eclipse.m2e</groupId>
    <artifactId>lifecycle-mapping</artifactId>
    <version>1.0.0</version>
    <configuration>
    <lifecycleMappingMetadata>
    <pluginExecutions>
    <pluginExecution>
    <pluginExecutionFilter>
    <groupId>
    org.apache.portals.pluto
    </groupId>
    <artifactId>
    maven-pluto-plugin
    </artifactId>
    <versionRange>
    [2.0.3,)
    </versionRange>
    <goals>
    <goal>assemble</goal>
    </goals>
    </pluginExecutionFilter>
    <action>
    <ignore></ignore>
    </action>
    </pluginExecution>
    </pluginExecutions>
    </lifecycleMappingMetadata>
    </configuration>
    </plugin>
    </plugins>
    </pluginManagement>
    </build>
     
    <!-- Repositories -->
    <repositories>
    <repository>
    <id>maven2-repository.dev.java.net</id>
    <url>http://download.java.net/maven/2</url>
    </repository>
    <repository>
    <id>maven2-repository.jboss.org</id>
    <url>http://repository.jboss.org/nexus/content/groups/public-jboss</url>
    </repository>
    <repository>
    <id>maven2-repository-portletfaces.org</id>
    <url>http://repository.portletfaces.org/content/repositories/portletfaces-releases</url>
    </repository>
    <repository>
    <id>prime-repo</id>
    <name>PrimeFaces Maven Repository</name>
    <url>http://repository.primefaces.org</url>
    <layout>default</layout>
    </repository>
    </repositories>
    </project>
  • Run the maven command mvn install to have the build war file automatically deployed to your Pluto portal server. You can also run this with Eclipse IDE – just select Run As → Maven Install
  • Now if you go to your Pluto Admin page, you will see your Portlet deployed there. You can simply create a new Portal page with a name of your choice and add this Portlet on it or add this Portlet on an existing Portal page to view / edit / help with the portlet.
weatherPortlet shown on the Pluto Admin Page

weatherPortlet shown on the Pluto Admin Page

weatherPortlet added on Source Allies Weather Portal

weatherPortlet added on Source Allies Weather Portal

<Context path=”/SimplePortlet” docBase=”SimplePortlet” crossContext=”true” />

4 comments

  1. Cool example, but unfortunately the code formatting isn’t quite right as all the indenting seems to be missing.

    Also, I think the autogenerated comments (like “return the weatherServiceClient”) don’t add much. This is exactly what the method signature already says. We don’t learn much from it, do we?

    I know it’s a Spring example, but just wanted to mention that if you deploy to a Java EE server you don’t have to bundle JSF and EL and also don’t necessarily have to configure it in web.xml (it’s active by default, just like e.g. JSP is active in Servlet container).

    I also wonder why you put some output texts in an h:outputText. In the h3 for “Weather at Zip Code:” you put the EL directly on the Facelet, so it seems you do know this is possible 😉 You can shorten the code by doing the same for the other output (except for currentTime, where it’s really needed for the Id)

    Hope these comments are helpful to you 😉 Keep up the good work!

  2. Hi Lal,
    good example of JSF/PrimeFaces & Spring. Just wat I needed to get me into developing an application using portlets. Thanks

Comments are closed.