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.