Chapter 21. Portlet Development Resources
21.1. JSR-168 and JSR-286 overview
The Java Community Process (
JCP) uses Java Specification Requests (JSRs) to define proposed specifications and technologies designed for the Java platform.
Portlet Specifications aim at defining portlets that can be used by any JSR-168 (Portlet 1.0) or JSR-286 (Portlet 2.0) portlet container.
The Red Hat JBoss Portal includes a container that supports both versions.
This chapter gives a brief overview of the Portlet Specifications. Portlet developers are strongly encouraged to read the JSR-286 Portlet Specification, which is available at http://www.jcp.org/en/jsr/detail?id=286.
The portal offers complete JSR-286 compliance. Any compliant JSR-168 or JSR-286 portlet operates inside the portal as mandated by the respective specifications.
21.1.1. Portal Pages
A portal can be considered as a series of web pages with different areas within them. Those areas contain different windows and each window contains a portlet:
The diagram below visually represents this nesting:
21.1.2. Rendering Modes
A portlet can have different view modes. Three modes are defined by the JSR-286 specification:
- View
- Generates markup reflecting the current state of the portlet.
- Edit
- Allows a user to customize the behavior of the portlet.
- Help
- Provides information to the user as to how to use the portlet.
21.1.3. Window States
Window states are an indicator of how much page space a portlet consumes on any given page. The three states defined by the JSR-286 specification are:
- Normal
- A portlet shares this page with other portlets.
- Minimized
- A portlet may show very little information, or none at all.
- Maximized
- A portlet may be the only portlet displayed on this page.
21.2. Tutorials
The tutorials contained in this chapter are targeted toward portlet developers. It is also recommended that developers read and understand the JSR-286 Portlet Specification .
Maven
This example is using Maven to compile and build the web archive. Maven versions can be downloaded from maven.apache.org
21.2.1. Deploying your first portlet
This section describes how to deploy a portlet in the Red Hat JBoss Portal (JBoss Portal).
An example portlet called
SimplestHelloWorld is available in the /jboss-jpp-VERSION-src/portal/examples/portlets/ directory of the JBoss Portal sources package.
21.2.1.1. Compiling
To compile and package the application:
- Navigate to the application directory and execute:
mvn package
- If the example is successfully packaged, the result will be available in:
gatein-simplest-helloworld-6.1.0.GA.war. - Copy the package file into
$JPP_HOME/standalone/deployments. - Start the portal (if it is not already running).
- Add the new portlet to the Application Registry.
- Create a new portal page and add the portlet to it.
21.2.1.2. Package Structure
Like other Java EE applications, the Red Hat JBoss Portal portlets are packaged in
WAR files. A typical portlet WAR file can include servlets, resource bundles, images, HTML, JavaServer Pages (JSP), and other static or dynamic files.
The following is an example of the directory structure of the
SimplestHelloWorld portlet.
Example 21.1. Portlet Directory Structure Explanation
|-- SimplestHelloWorld-0.0.1.war | `-- WEB-INF | |-- classes | | `-- org | | `-- jboss | | `-- portal | | `-- portlet | | `-- samples | | `-- SimplestHelloWorldPortlet.class | |-- portlet.xml | `-- web.xml
Directory Structure Elements
- SimplestHelloWorldPortlet.class
- The compiled Java class, which implements javax.portlet.Portlet through javax.portlet.GenericPortlet.
- portlet.xml
- The mandatory descriptor file for portlets, which is used during deployment.
- web.xml
- The mandatory descriptor for web applications.
21.2.1.3. Portlet Class
Below is the Java source for an example portlet named
SimplestHelloWorldPortlet.
Note
Portlets are responsible for generating markup fragments, as they are included on a page and are surrounded by other portlets. This means that a portlet outputting HTML must not output any markup that cannot be found in a
<body> element.
Example 21.2. SimplestHelloWorldPortlet Explanation
package org.jboss.portal.portlet.samples; import java.io.IOException; import java.io.PrintWriter; // Comment #1 import javax.portlet.GenericPortlet; import javax.portlet.RenderRequest; import javax.portlet.RenderResponse; public class SimplestHelloWorldPortlet extends GenericPortlet { // Comment #2 public void doView(RenderRequest request, RenderResponse response) throws IOException { // Comment #3 PrintWriter writer = response.getWriter(); // Comment #4 writer.write("Hello World !"); // Comment #5 writer.close(); } }
- Comment #1
- All portlets must implement the
javax.portlet.Portletinterface. TheGenericPortletclass provides a default implementation for the Portlet interface.Thejavax.portlet.GenericPortletclass implements therendermethod to dispatch to abstract mode-specific methods. This makes it easier to support the standard portlet modes.GenericPortletalso provides a default implementation for theprocessAction,initanddestroymethods. It is recommended to extendGenericPortletfor most cases. - Comment #2
- If only the
viewmode is required, then only thedoViewmethod needs to be implemented. TheGenericPortletrender implementation calls our implementation when theviewmode is requested. - Comment #3
- To obtain a writer that can produce content, use the
response.GetWriter()method from the RenderResponse object. - Comment #4
- Write the markup to display.
- Comment #5
- Closing the writer.
21.2.1.4. Application Descriptors
The portal requires certain descriptors to be included in a portlet
WAR file. These descriptors are defined by the Java EE (web.xml) and Portlet Specification (portlet.xml).
Below is an example of the
SimplestHelloWorldPortlet/WEB-INF/portlet.xml file. This file must adhere to its definition in the JSR-286 Portlet Specification. More than one portlet application may be defined in this file.
Example 21.3. The portlet.xml File Explanation
<portlet-app xmlns="http://java.sun.com/xml/ns/portlet/portlet-app_2_0.xsd" 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" version="2.0"> <portlet> <!-- Comment #1 --> <portlet-name>SimplestHelloWorldPortlet</portlet-name> <!-- Comment #2 --> <portlet-class> org.jboss.portal.portlet.samples.SimplestHelloWorldPortlet </portlet-class> <!-- Comment #3 --> <supports> <mime-type>text/html</mime-type> </supports> <!-- Comment #4 --> <portlet-info> <title>Simplest Hello World Portlet</title> </portlet-info> </portlet> </portlet-app>
Notes
- Comment #1
- Define the portlet name. It does not have to be the class name.
- Comment #2
- The Fully Qualified Name (
FQN) of your portlet class must be declared here. - Comment #3
- The
<supports>element declares all of the markup types that a portlet supports in therendermethod. This is accomplished via the<mime-type>element, which is required for every portlet.The declared MIME types must match the capability of the portlet. It allows administrators to pair which modes and window states are supported for each markup type. This does not have to be declared as all portlets must support theviewportlet mode.Use the<mime-type>element to define which markup type the portlet supports. In the example above this istext/html. This section tells the portal to only outputHTML. - Comment #4
- When rendered, the portlet's title is displayed as the header in the portlet window, unless it is overridden programmatically. In the example above the title would be
Simplest Hello World Portlet.
21.2.2. JavaServer Pages Portlet Example
This section discusses:
- Adding more features to the previous example.
- Using a JSP page to render the markup.
- Using the portlet tag library to generate links to the portlet in different ways.
- Using the other standard portlet modes.
Note
The example used in this section is available in the directory of the portal sources package.
Procedure 21.1. Compile JavaServer Pages Portlet
- Obtain the Red Hat JBoss Portal sources package from the Customer Support portal.
- Move to
/jboss-jpp-VERSION-src/portal/examples/portlets/jsphellouser - Execute
mvn package. - Copy
jsphellouser/target/gatein-jsp-hellouser-6.1.0.GA.warto thedeploydirectory of JBoss Application Server. - Add the new portlet to the Application Registry.
- Create a new portal page and add the portlet to it.
21.2.2.1. Package Structure
The package structure in this tutorial does not differ greatly from the previous example, with the exception of adding some JSP files which are detailed later.
The
JSPHelloUser portlet contains the mandatory portlet application descriptors. The following is an example of the directory structure of the JSPHelloUser portlet:
gatein-jsp-hellouser->1.0.0-GA-SNAPSHOT.war |-- META-INF | |-- MANIFEST.MF |-- WEB-INF | |-- classes | | `-- org | | `-- jboss | | `-- portal | | `-- portlet | | `-- samples | | `-- JSPHelloUserPortlet.class | |-- portlet.xml | `-- web.xml `-- jsp |-- edit.jsp |-- hello.jsp |-- help.jsp `-- welcome.jsp
21.2.2.2. Portlet Class
The code below is from the
jsphellouser/src/main/java/org/jboss/portal/portlet/samples/JSPHelloUserPortlet.java Java source. It is split in different pieces.
Example 21.4. JSPHelloUserPortlet Explanation
package org.jboss.portal.portlet.samples; import java.io.IOException; import javax.portlet.ActionRequest; import javax.portlet.ActionResponse; import javax.portlet.GenericPortlet; import javax.portlet.PortletException; import javax.portlet.PortletRequestDispatcher; import javax.portlet.RenderRequest; import javax.portlet.RenderResponse; import javax.portlet.UnavailableException; public class JSPHelloUserPortlet extends GenericPortlet { // Comment #1 public void doView(RenderRequest request, RenderResponse response) throws PortletException, IOException { // Comment #2 String sYourName = (String) request.getParameter("yourname"); if (sYourName != null) { request.setAttribute("yourname", sYourName); // Comment #3 PortletRequestDispatcher prd = getPortletContext().getRequestDispatcher("/jsp/hello.jsp"); // Comment #4 prd.include(request, response); } else { //Code split between lines. Direct copy will result in parse errors. PortletRequestDispatcher prd = getPortletContext(). getRequestDispatcher("/jsp/welcome.jsp"); prd.include(request, response); } } ...
- Comment #1
- Override the doView method (as in the first tutorial).
- Comment #2
- This entry attempts to obtain the value of the render parameter named
yourname. If defined it should redirect to thehello.jspJSP page, otherwise to thewelcome.jspJSP page. - Comment #3
- Get a request dispatcher on a file located within the web archive.
- Comment #4
- Perform the inclusion of the markup obtained from the JSP.
As well as the
VIEW portlet mode, the specification defines two other modes; EDIT and HELP.
These modes need to be defined in the
portlet.xml descriptor. This will enable the corresponding buttons on the portlet's window.
The generic portlet that is inherited dispatches the different views to the methods:
doView , doHelp and doEdit.
... protected void doHelp(RenderRequest rRequest, RenderResponse rResponse) throws PortletException, IOException, UnavailableException { rResponse.setContentType("text/html"); PortletRequestDispatcher prd = getPortletContext().getRequestDispatcher("/jsp/help.jsp"); prd.include(rRequest, rResponse); } protected void doEdit(RenderRequest rRequest, RenderResponse rResponse) throws PortletException, IOException, UnavailableException { rResponse.setContentType("text/html"); PortletRequestDispatcher prd = getPortletContext().getRequestDispatcher("/jsp/edit.jsp"); prd.include(rRequest, rResponse); } ...
Portlet calls happen in one or two phases. One when the portlet is rendered and two when the portlet is actioned then rendered.
An action phase is a phase where a state changes. The render phase will have access to render parameters that will be passed each time the portlet is refreshed (with the exception of caching capabilities).
The code to be executed during an action has to be implemented in the processAction method of the portlet.
Example 21.5. processAction Explanation
... // Comment #1 public void processAction(ActionRequest aRequest, ActionResponse aResponse) throws PortletException, IOException, UnavailableException { // Comment #2 String sYourname = (String) aRequest.getParameter("yourname"); // Comment #3 aResponse.setRenderParameter("yourname", sYourname); } ...
- Comment #1
processActionis the method fromGenericPortletto override for the action phase.- Comment #2
- Here the parameter is retrieved through an action URL.
- Comment #3
- The value of
yournameis kept to make it available in the rendering phase. The previous line simply copies an action parameter to a render parameter for this example.
21.2.2.3. JSP files and the Portlet Tag Library
The
help.jsp and edit.jsp files are very simple. Note that CSS styles are used as defined in the portlet specification. This ensures that the portlet will render well within the theme and across portal vendors.
<div class="portlet-section-header">Help mode</div> <div class="portlet-section-body">This is the help mode, a convenient place to give the user some help information.</div>
<div class="portlet-section-header">Edit mode</div> <div class="portlet-section-body">This is the edit mode, a convenient place to let the user change his portlet preferences.</div>
The landing page contains the links and form to call our portlet.
Example 21.6. Landing Page Explanation
<!-- Comment #1 --> <%@ taglib uri="http://java.sun.com/portlet" prefix="portlet" %> <div class="portlet-section-header">Welcome !</div> <br/> <div class="portlet-font">Welcome on the JSP Hello User portlet, my name is GateIn Portal. What's yours ?</div> <br/> <div class="portlet-font">Method 1: We simply pass the parameter to the render phase:<br/> <!-- Comment #2 --> <a href="<portlet:renderURL><portlet:param name="yourname" value="John Doe"/> </portlet:renderURL>">John Doe</a></div> <br/> <div class="portlet-font">Method 2: We pass the parameter to the render phase, using valid XML: Please check the source code to see the difference with Method 1. <!-- Comment #3 --> <portlet:renderURL var="myRenderURL"> <portlet:param name="yourname" value='John Doe'/> </portlet:renderURL> <br/> <!-- Comment #4 --> <a href="<%= myRenderURL %>">John Doe</a></div> <br/> <div class="portlet-font">Method 3: We use a form:<br/> <!-- Comment #5 --> <portlet:actionURL var="myActionURL"/> <!-- Comment #6 --> <form action="<%= myActionURL %>" method="POST"> <span class="portlet-form-field-label">Name:</span> <input class="portlet-form-input-field" type="text" name="yourname"/> <input class="portlet-form-button" type="Submit"/> </form> </div>
- Comment #1
- The portlet taglib. This is required.
- Comment #2
- The first method showed here is the simplest one.
portlet:renderURLwill create a URL that calls the render phase of the current portlet and append the result at the place of the markup (within a tag). A parameter is also added directly to the URL. - Comment #3
- In this method the
varattribute is used. This avoids having one XML tag within another. Instead of printing the URL theportlet:renderURLtag will store the result in the referenced variable (myRenderURL). - Comment #4
- The variable
myRenderURLis used like any other JSP variable. - Comment #5
- The third method mixes form submission and action request. Again, a temporary variable is used to put the created URL into.
- Comment #6
- The action URL is used in HTML form.
In the third method, the action phase is triggered first then the render phase is triggered, which outputs some content back to the web browser based on the available render parameters.


