Tutorial:

JSR-286 Development Tutorial: JSPs, MVC and the portlet tag library

By Cameron McKenzie

TheServerSide.com

The following JSR-286 tutorial, written by Cameron McKenzieand Sal Pece, explores how to forward to Java Server Pages (JSPs)from a portlet, while at the same time leveraging various Portlet 2.0 API artifcats within the JSP by properly referencing the portlet tag library. By using portlets as controllers, delegating complex business logic to JavaBeans or even a RESTful or SOAP-based service layer, and using JSPs to generate the user interface, developers are effectively embracing the proven model-view-controllerdesign strategy.

Developing portlet based applications is similar in many ways to developing web based apps using Struts, Spring or Seam.

Cameron McKenzie, editor of TheServerSide.com

In a good model-view-controller type of application, a Java-centric component should never be polluted with lots of lousy HTML. With a typical servlet, Struts and SpringMVC-based applications, HTML is typically generated by a Java Server Page (JSP). In this regard, good portlet applications are no different. However, portlet applications do present some unusual complications when deferring to a JSP for markup generation. For example, how does a JSP link back to a specific portlet on a page? How does a portlet invoke a JSP? How do we gain access to the portlet-specific PortletRequest and PortletResponse object in JSP? After all, the JSP specification only provides for access to the HttpRequest and HttpResponse within JSP scrpitlets and expressions.

This tutorial deals with basic JSP development, and the issues that present themselves when deferring to a JSP for markup generation.

Deferring to a JSP for markup generation

While accessing the PrintWriter from the request object and printing content directly back to the client in the doView method of a portlet is easily accomplished, it certainly isn't a best practice.

We have been spoiled so far with portlets that are relatively light on HTML tags. However, for content generation, a portlet should defer to a Java Server Page (JSP). JSPs are Web-centric artifacts that are written largely in static HTML, but can be interspersed with Java code to make them more interactive.

The following is the code for a Java Server Page that we will save in a file named welcome.jsp. As you can see from the code below, a JSP is mostly markup, with a little bit of Java code interspersed. Java Server Pages facilitate the development of complex, dynamic Web pages.

<%@ page session="false" contentType="text/html" %>
<B>Welcome to this simple JSP</B>
<BR>We did some snooping on you.
<BR>This is what we learned about your browser:
<BR><I> <%=request.getHeader("user-agent")%>  </I>
<BR>And we know what language you speak, it's:
<I> <%=request.getLocale().getDisplayLanguage()%> </I>

Invoking the welcome.jsp from a portlet

While the concept of delegating to a JSP for view generation is relatively simple and straightforward, the code is actually a little bit intimidating. Assuming the HTML code above was saved in a file named welcome.jsp, and that welcome.jsp file was saved in the root of the web application archive (WAR), invoking the welcome.jsp would require the following lines of code in order to be invoked from a portlet:

String url = "welcome.jsp";
getPortletContext().getRequestDispatcher(url).include(request,response);

When a particular portlet is requested, the custom-coded Java class that both extends GenericPortlet and is specified in the portlet.xml file will be invoked by the portal server. The portlet class is then responsible for implementing any required logic and then delegating to a JSP for markup generation. This is achieved using the include method of the PortletRequestDispatcher, during the portlet's rendering phase. This is a bit different from typical servlet-based development where you typically forward to a JSP, instead of performing an include. However, the forward method closes the output stream after it is invoked, whereas the include method does not. Since other portlets on the page will need to use the same output stream to deliver content to the client, the include method must be used when delegating to a JSP, not the forward method.

Class diagram for the PortletRequestDispatcher
    Figure 1. Class diagram for the PortletRequestDispatcher.

The full code for the JSPDisplay portlet that forwards to the welcome.jsp file is as follows:

package com.mcnz.portlet;
import java.io.*; import javax.portlet.*;
public class JSPDisplay extends GenericPortlet {  
 protected void doView (RenderRequest request, RenderResponse response)                                    
                          throws PortletException, IOException {    
   String url = "/welcome.jsp";    
  getPortletContext().getRequestDispatcher(url).include(request,response);  
 }
}

Where is the portal finding the JSP?

Legacy portal development tools would pull JSP files from a variety of different folders, depending upon the client device and the preferred language of the user making the request. For JSR-286 portlets, the PortletRequestDispatcher quite sensibly searches for jsp files starting from the root of the war.

Location of the welcome.jsp file inside the WAR
    Figure 2. Location of the welcome.jsp file inside the WAR.

So, with the JSPDisplay portlet, the welcome.jsp file would be found right there in the root. Here's how the whole thing looks when it's actually run on the test portal.

Result of running the JSPDisplay portlet
    Figure 3. Result of running the JSPDisplay portlet.

Deployment descriptor for the JSPDisplay portlet

Assuming the JSPDisplay portlet is packaged in its own WAR file, the portlet.xml file for the JSPDisplay portlet would be as follows:

<?xml version="1.0" encoding="UTF-8"?>
<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" id="com.mcnz.portlet.JSPDisplay.9bb8c08ce3">
    <portlet>
         <portlet-name>JSPDisplay</portlet-name>
         <display-name>JSPDisplay</display-name>
         <portlet-class>com.mcnz.portlet.JSPDisplay</portlet-class>
         <supports>
            <mime-type>text/html</mime-type>
            <portlet-mode>view</portlet-mode>
         </supports>
    </portlet>
    <default-namespace>http://JSPDisplay/</default-namespace>
</portlet-app>

Is something wrong with our welcome.jsp?

Portlets build extensively upon the Servlet and JSP API, and the welcome.jsp file was coded as though it were part of a typical servlet and JSP application. When you're doing portlet development, not respecting your jsp files as portlet artifacts is a very, very bad thing.

A Java Server Page, by virtue of the fact that it runs in a Java-based Web container, has implicit access to eight very important object types defined by the Servlet and JSP API, namely: the ServletRequest, ServletResponse, ServletConfig, ServletContext, HttpSession, JSPWriter, pageContext and HttpJspPage object.

Now, we're actually not supposed to access these implicit variables within our portlet jsps. Remember, with portlets, we don't use the ServletRequest and ServletResponse objects, but instead, we use the RenderRequest and RenderResponse objects.

Sadly, the RenderRequest and RenderResponse objects are not implicitly available to JSPs that run within a portlet application. However, the Portlet API does provide a special custom tag that indeed makes it possible to access these important objects. Any Java Server Page that needs easy and implicit access to classes defined in the Portlet API needs only to add a single, special custom tag, portlet:defineObjects, to their JSP page. This tag makes the RenderRequest, RenderResponse, and even the PortletConfig object implicitly available with the names renderRequest, renderResponse and portletConfig.

There are two configuration steps required to use the <portlet:defineObjects/> custom tag, namely:

1.  A taglib directive must be added to the top of the JSP page that uses the portlet.tld custom tags

<%@taglib uri="http://java.sun.com/portlet" prefix="portlet"%>

2.  The <portlet:defineObjects/> custom tag must appear somewhere in the portlet JSP page, with convention being that it is added toward the top of the page.

<portlet:defineObjects/>

After defining the taglib in the web.xml file, you must add a taglib directive, and the <portlet:defineObjects/> tag, to your JSP. After those elements have been added, you have implicit access to the variables named renderRequest, renderResponse and portletConfig. Here's how our JSP looks when we bring all of the HTML scriptlets and JSR-286 elements together in the welcome.jsp file. Notice that the getHeader call has been changed to getProperty to comply with the Portlet API:

<%@ page session="false" contentType="text/html"  %>
<%@taglib uri="http://java.sun.com/portlet" prefix="portlet" %>
<portlet:defineObjects/>
<B>Welcome to this simple JSP</B>
<BR>We did some snooping on you.
<BR>This is what we learned about your browser:
<BR><I> <%= renderRequest.getProperty("user-agent")%>  </I>
<BR>And we know what language you speak, it's:
<I>     <%= renderRequest.getLocale().getDisplayLanguage()%> </I>

When the updated welcome.jsp file runs on the server, the result is exactly the same as before. The difference is merely in the implementation where the updated JSP stays in compliance with the Portlet API, and avoids using the components defined in the Servlet and JSP API.

Result of running the updated welcome.jsp file
    Figure 4. Result of running the updated welcome.jsp file.

Summary

In many ways, developing portlet-based applications is similar to developing Web-based applications using Struts, Spring, Seam and even just the Servlet and JSP API. Like many frameworks, portlet development embraces the model-view-controller design philosophy that has portlets themselves act in many ways as a controller, delegating complex computing tasks to other components and services that can be thought of as more of a model, while at the same time delegating to JSPs that can act as view generators as they render HTML for display on the client machine. And by using the PortletRequestDispatcher, and remembering to include JSP content and not forwarding to them, embracing a good MVC design philosophy in your portlet applications will be as easy as a lead-pipe cinch.

Do you have any quick tips for mastering Portlet API development? Let us know.

Follow Cameron McKenzie on Twitter (@potemcam).

30 May 2013

Related Content

Related Resources