Chapter 23. Basic JSF Portlet Development

JSF stands for JavaServer Pages. The JSF version delivered by the built-in Portlet Bridge is 2.1.

23.1. Example Code

This section cites code from JSF2 Hello World Portlet from the Quickstarts Collection .

23.1.1. pom.xml

There is only one noticeable difference in pom.xml against what we have shown as a general case in the Starting a Portlet Project section: we only need to add JSF-specific dependencies:

Example 23.1. pom.xml


<dependencies>
    <!-- 
   The versions, scopes and types of these dependencies are managed in gatein-*-bom.
   You need to name only groupId and artifactId here.
   Name only those artifacts you refer to in your code.
   Look at gatein-*-bom POM file for the complete list of available artifacts.
    -->
    <dependency>
   <groupId>org.jboss.spec.javax.faces</groupId>
   <artifactId>jboss-jsf-api_2.1_spec</artifactId>
    </dependency>
    <dependency>
   <groupId>org.jboss.portletbridge</groupId>
   <artifactId>portletbridge-api</artifactId>
    </dependency>
</dependencies>

23.1.2. JSF Template Files

Example 23.2. Beginning of a JSF portlet template

This example shows the start of a typical JSF portlet template declaration. It is taken from main.xhtml file located in the src/main/webapp/pages directory.

<f:view xmlns="http://www.w3.org/1999/xhtml"  xmlns:f="http://java.sun.com/jsf/core" xmlns:h="http://java.sun.com/jsf/html">
	<!-- the f:view above prevents an erroneous <html> within <body> coming from portal. -->
	<!-- <h:head /> and <h:body> in the following are always needed otherwise JSF Facelets will not work -->
	<h:head />
	<h:body styleClass="jsf2HelloWorldPortlet">
	    <h:outputStylesheet library="css" name="jsf2-hello-world-portlet.css" />
	    <h2>JSF2 Hello World Portlet</h2>
Note that <f:view> as a root element of the portlet template above prevents an erroneous <html> within <body> coming from portal. Moreover, the <h:head> and <h:body> elements are always needed for JSF Facelets to work.

Example 23.3. A form in a JSF portlet template

This example demonstrates how to use several JSF elements, such as <h:outputLabel> , <h:inputText> and <h:commandButton> within <h:form>.

<h:form id="jsf2HelloWorldPortlet">
   <h:outputLabel value="#{msgs.Name}" for="nameInput"/>
   <h:inputText id="nameInput" value="#{helloBean.name}">
       <f:ajax render="output" event="keyup"/>
   </h:inputText>
   <br />
   
   <p>
       <h:panelGroup id="output">
           <strong>
               <h:outputFormat value="#{msgs.Hello_0}" rendered="#{not empty helloBean.name}">
                   <f:param value="#{helloBean.name}" />
              </h:outputFormat>
           </strong>
       </h:panelGroup>
   </p>
   
   <h:commandButton id="reset" value="#{msgs.Reset}" actionListener="#{helloBean.reset}">
       <f:ajax render="@form" />
   </h:commandButton> - #{msgs.ResetComment}
   <br />
   <h:commandButton id="reload" value="#{msgs.Reload}" /> - #{msgs.ReloadComment}
   <br />
   
   <h:messages />
</h:form>
The complete source code of the above template is located in src/main/webapp/pages/main.xhtml of JSF2 Hello World Portlet project.

23.1.3. Java Beans

In the JSF template file shown above, we reference the helloBean bean. This bean is implemented in Java as follows:

Example 23.4. helloBean Implementation


/**
* {@link HelloBean} is the JSF backing bean for the application, holding the input data to be re-displayed.
*/
@ManagedBean(name = "helloBean")
@SessionScoped
public class HelloBean implements Serializable {

   private static final long serialVersionUID = -6239437588285327644L;

   /**
    * Stores the name which will be used to greet the application user.
    */
   private String name;

   /**
    * Initializes {@link #name} with the value {@code "World"}.
    */
   @PostConstruct
   public void postContruct() {
       this.name = "World";
   }

   /**
    * Returns {@link #name}.
    * 
    * @return {@link #name}
    */
   public String getName() {
       return name;
   }

   /**
    * Set {@link #name}.
    * 
    * @param name
    */
   public void setName(String name) {
       this.name = name;
   }

   /**
    * Resets {@link #name} to the default value {@code "World"}.
    * 
    * @param ae ignored
    */
   public void reset(ActionEvent ae) {
       this.name = "World";
   }

}
The @ManagedBean and @SessionScoped annotations allow for omitting of equivalent declarations in the faces-config.xml file.

23.1.4. portlet.xml

portlet.xml is the place where we tie the JSF templates with the portlet.

Example 23.5. portlet.xml


<portlet-app xmlns="http://java.sun.com/xml/ns/portlet/portlet-app_2_0.xsd" version="2.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    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>
        <description>A simple JSF2 portlet.</description>
        <portlet-name>jsf2HelloWorldPortlet</portlet-name>
        <display-name>JSF2 Hello World Portlet</display-name>
        <portlet-class>javax.portlet.faces.GenericFacesPortlet</portlet-class>
        <init-param>
            <name>javax.portlet.faces.defaultViewId.view</name>
            <value>/pages/main.xhtml</value>
        </init-param>
        <init-param>
            <name>javax.portlet.faces.defaultViewId.edit</name>
            <value>/pages/edit.xhtml</value>
        </init-param>
        <init-param>
            <name>javax.portlet.faces.defaultViewId.help</name>
            <value>/pages/help.xhtml</value>
        </init-param>
        <init-param>
            <name>javax.portlet.faces.preserveActionParams</name>
            <value>true</value>
        </init-param>
        <expiration-cache>0</expiration-cache>
        <supports>
            <mime-type>text/html</mime-type>
            <portlet-mode>VIEW</portlet-mode>
            <portlet-mode>EDIT</portlet-mode>
            <portlet-mode>HELP</portlet-mode>
        </supports>
        <portlet-info>
            <title>JSF2 Hello World Portlet</title>
        </portlet-info>
        <container-runtime-option>
            <name>org.gatein.pc.remotable</name>
            <value>true</value>
        </container-runtime-option>
    </portlet>
</portlet-app>


Note that the javax.portlet.faces.defaultViewId.*init-params are used to bind the JSF templates with the respective portlet view modes. javax.portlet.faces.GenericFacesPortlet as a <portlet-class> will serve the purpose for most JSF portlets.

23.1.5. web.xml

JSF portlets require a few tweaks in the web.xml file:

Example 23.6. web.xml


<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_2_5.xsd" version="2.5">
    <display-name>jsf2-hello-world-portlet</display-name>
    <context-param>
        <description>See https://docs.jboss.org/author/display/PBR/Render+Policy</description>
        <param-name>javax.portlet.faces.RENDER_POLICY</param-name>
        <param-value>ALWAYS_DELEGATE</param-value>
    </context-param>
    
    <!-- The following params are documented here: http://myfaces.apache.org/core21/myfaces-impl/webconfig.html -->
    <context-param>
        <param-name>javax.faces.FACELETS_VIEW_MAPPINGS</param-name>
        <param-value>*.xhtml</param-value>
    </context-param>
    <context-param>
        <param-name>facelets.DEVELOPMENT</param-name>
        <param-value>false</param-value>
    </context-param>
    <context-param>
        <param-name>javax.faces.DEFAULT_SUFFIX</param-name>
        <param-value>.xhtml</param-value>
    </context-param>
    
    <servlet>
        <servlet-name>Faces Servlet</servlet-name>
        <servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>Faces Servlet</servlet-name>
        <url-pattern>*.faces</url-pattern>
    </servlet-mapping>
</web-app>

23.1.6. Custom CSS

Portlet Bridge supports loading of CSS resources in the "JSF way". Just use the <h:outputStylesheet library="css" name="jsf2-hello-world-portlet.css" /> as we do in the main.xhtml file above. The jsf2-hello-world-portlet.css file needs to be placed in resources/css folder of the web application.
Note that relative paths like url('css/background/jsf-logo.png') do not work when used in CSS loaded via <h:outputStylesheet ...> . Rather a JSF Expression Language expression #{resource['/css/background/jsf-logo.png'] } needs to be used. This expression is dynamically evaluated to a proper public URL. The path '/css/background/jsf-logo.png' used in the expression is relative to resources folder of the web application. See also Resource Serving .

Example 23.7. jsf2-hello-world-portlet.css

17. div.jsf2HelloWorldPortlet {
18.     padding: 10px;
19.     /* In the following we use a JSF Expression Language expression rather then plain relative path. 
20.        Plain relative paths do not work in JSF portlets. The expression #{resource['...']} is 
21.        dynamically evaluated to a proper public URL. The path '/css/background/jsf-logo.png' 
22.        used in the expression is relative to  resources folder of this web application.
23.        See https://docs.jboss.org/author/display/PBR/Resource+Serving */
24.     background: url(#{resource['/css/background/jsf-logo.png']}) no-repeat;
25.     background-position-x: 753px;
26.     background-position-y: 10px;
27. }
28. div.jsf2HelloWorldPortlet p {
29.     width: 713px; 
30. }

23.1.7. Internationalization

Internationalization is supported via standard Java Resource bundles. In our example project the *.property files of org.jboss.as.quickstarts.jsf.messages resource bundle are stored under src/main/resources/org/jboss/as/quickstarts/jsf . The following settings in faces-config.xml are needed so that this bundle can be used in JSF templates.

Example 23.8. faces-config.xml

<faces-config 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/web-facesconfig_2_0.xsd" version="2.0">
    <application>
        <!-- Declare the internationalization resources -->
        <resource-bundle>
            <!-- The resource bundle property files are in src/main/resources/org/jboss/as/quickstarts/jsf -->
            <base-name>org.jboss.as.quickstarts.jsf.messages</base-name>
            <var>msgs</var>
        </resource-bundle>
        <locale-config>
            <default-locale>en</default-locale>
            <supported-locale>de</supported-locale>
        </locale-config>
    </application>
</faces-config>
Note that in the above faces-config.xml, we have made our bundle visible in JSF templates under the variable msgs . Its individual entries can then be accessed using the usual Expression Language dot notation: e.g. #{msgs.Name }.

23.2. Further Steps

After having done all the above, it is time to build and deploy the portlet , import it and add it to a page so that you can test its functionality.