Skip to main content

By clicking Submit, you agree to the developerWorks terms of use.

The first time you sign into developerWorks, a profile is created for you. Select information in your profile (name, country/region, and company) is displayed to the public and will accompany any content you post. You may update your IBM account at any time.

All information submitted is secure.

  • Close [x]

The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerworks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

By clicking Submit, you agree to the developerWorks terms of use.

All information submitted is secure.

  • Close [x]

Build and test JSR 168-compliant portlets with Apache Pluto

Are your portlets compliant with the Portlet Specification reference implementation?

Kulvir Singh Bhogal (kbhogal@us.ibm.com), Senior IT Specialist, IBM
Kulvir Singh Bhogal works as an IBM Software Services for WebSphere consultant, devising and implementing J2EE solutions at customer sites across the United States.
Mark Talbot (talbotm@us.ibm.com), Software Engineer, IBM
Mark Talbot photo
Mark Talbot works for IBM's Industry Solutions, developing applications for the financial sector. You can reach Mark at talbotm@us.ibm.com.

Summary:  With Apache Pluto, Java™ developers have a freely available tool for testing whether their portlets comply with the JSR 168 Portlet Specification. Developers Mark Talbot and Kulvir Singh Bhogal take you on a guided tour of portlet testing. You'll install Pluto and build, compile, package, and deploy a simple portlet to Pluto to test it for JSR 168 compliance. You'll also get a hint of what's in store for the next version of the Portlet Specification.

Date:  25 Apr 2006
Level:  Introductory

Activity:  21389 views
Comments:  

Develop skills on this topic

This content is part of a progressive knowledge path for advancing your skills. See Java portlet development

In October 2003, the Java Community Process issued the final release of Java Specification Request (JSR) 168: the Portlet Specification (see Resources). JSR 168 articulates the first programming standard for Java portlet development. Previously, a portlet developed for WebSphere Portal Server, for example, couldn't run in another portal container such as BEA WebLogic Portal. A portal container isn't a required component for a J2EE application server. Nevertheless, this lack of portability was a deviation from standard J2EE enterprise applications, which (when built according to spec) can be deployed to any J2EE-compliant application server. Lack of portlet portability and the associated vendor lock-in deterred businesses from buying portal servers. By putting an end to portlet-development anarchy, JSR 168 has laid those businesses' fears to rest.

The JSR 168 Portlet API is quite extensive. This article isn't intended to be a JSR 168 tutorial, so we won't delve deeply into the API. If you're unfamiliar with the JSR 168 API, we suggest you spend some time getting yourself up to speed with some of the materials in Resources.

Java developers have a freely available tool for testing that they've written their portlets in accordance with the Portlet Specification. Apache Pluto is the reference implementation for JSR 168. It is a portlet container that implements the Portlet API. Portlet containers like Pluto and IBM WebSphere Portal Server serve as the runtime environment for portlets, much the way a servlet is powered by the runtime environment of a Web application server's servlet container. However, the portlet container is not standalone; it lives on top of a servlet container and relies on its services. In this article, we'll show you how to write a simple portlet and test it against the Pluto portlet container.

Installing Pluto

Apache Pluto requires Java SE 5. If you haven't already installed this version of the JDK, download and install it to proceed with this article's exercise (see Resources).

If JAVA_HOME is already set to a previous version of the JVM that's installed on your system, changing it could break your existing JVM-dependent applications. If you already have an older JVM installed, you should update the JAVA_HOME variable directly inside of the Pluto startup script: startup.bat on Windows systems or startup.sh on Linux.

Next, you need to set or change the JAVA_HOME environment variable, which Pluto references to locate your JVM. (The Sun installer does not set the value of JAVA_HOME by default.) If you do not have a previous JVM version installed on your system, follow these steps (these instructions assume that you are running Windows):

  1. Right-click My Computer and select Properties from the context menu.
  2. Click the Advanced tab.
  3. At the bottom of the window, click the Environment Variables button.
  4. In the System variables pane, click New.
  5. Enter JAVA_HOME for the variable name. For the variable value, enter the directory containing the Sun JVM install.

Figure 1 shows what the value of JAVA_HOME would be if you chose to install the Java 5.0 SDK to the C:\Program Files\IBM\Java50 directory:


Figure 1. Changing the JAVA_HOME environment variable

Now that your Java environment is properly set up, download the ZIPet file containing the binaries for Pluto (pluto-current.zip) from Apache's Web site (see Resources).

Verifying the download

Assuming you're as security-conscious as we are, you'll want to be sure that the ZIP file download did come from Apache Software Foundation. The files are digitally signed using both PGP and md5. Using GnuPG (see Resources) and the ASCII armor file (pluto-current.zip.asc), you can verify the authenticity of this download.

First, add the Apache Pluto public key to your public key ring by entering the command shown in the top line of Listing 1. The KEYS file is available on the Pluto download page.


Listing 1. Import the KEYS file

C:\>gpg --import KEYS
gpg: key E41EDC7E: public key "Carsten Ziegeler <cziegeler@apache.org>" importe

gpg: key 320B4FB4: public key "Nick Lothian (Apache) <nlothian@apache.org>" imp
rted
gpg: key DD4200EA: public key "David H. DeWolf <david@daviddewolf.com>" importe

gpg: Total number processed: 3
gpg:               imported: 3
gpg: 3 marginal(s) needed, 1 complete(s) needed, PGP trust model
gpg: depth: 0  valid:   1  signed:   0  trust: 0-, 0q, 0n, 0m, 0f, 1u
gpg: next trustdb check due at 2011-03-08

Next, enter the command shown in the top line of Listing 2 to verify the signed ZIP file you received from Apache:


Listing 2. Verify pluto-1.0.1.zip.asc

C:\>gpg --verify pluto-1.0.1.zip.asc
gpg: Signature made 10/19/05 09:11:31 using DSA key ID DD4200EA
gpg: Good signature from "David H. DeWolf <david@daviddewolf.com>"
gpg:               aka "David H. DeWolf <ddewolf@apache.org>"
gpg:               aka "David H. DeWolf <ddewolf@rocketmail.com>"
gpg:               aka "David H. DeWolf <ddewolf@gmail.com>"
gpg:               aka "David H. DeWolf <david.dewolf@digitalfocus.com>"
gpg: WARNING: This key is not certified with a trusted signature!
gpg:          There is no indication that the signature belongs to the owner.
Primary key fingerprint: 6AA5 5850 9A7B 275C E0BC  2851 B217 63FA DD42 00EA

If the gpg --verify command generates output similar to what's displayed in Listing 2, you can be confident that the Pluto archive file is in fact from Apache. You can ignore the warning indicating that the signature is not trusted. The only way to guarantee that the public key signature is from the owner is for the owner to hand you the key on a disk, in person. However, with the steps you've taken, you can be reasonably certain that the ZIP file you downloaded from Apache has not been compromised. (See Resources for more information on verifying Apache downloads.)

Unzipping the Pluto download

Now you're ready to extract the ZIP file onto your machine. We'll assume you're unzipping Pluto into the root directory of your C:\ drive:

C:\>unzip pluto-current.zip

This creates a C:\pluto-1.0.1 directory that includes a bin subdirectory. Navigate to the bin subdirectory and enter startup.bat at the command prompt to start the Pluto server.

You'll administer and view your portlets from the Pluto home page, shown in Figure 2. Launch your Web browser and navigate to http://localhost:8080/pluto/portal.


Figure 2. The Pluto home page
XML error: The image is not displayed because the width is greater than the maximum of 580 pixels. Please decrease the image width.

Note: If the Pluto home page does not appear, check to make sure that your firewall is not preventing Pluto from accepting connections.

Now that you have Pluto up and running, you'll create a simple portlet and use Pluto to test it for JSR 168 compliance.


Developing a JSR 168 portlet

To see how to use Pluto as a JSR 168-compliant test bed for your portlets, you need a portlet to test. For this exercise, you'll create a simple portlet that, depending on user input, converts the contents of a text box to all uppercase or all lowercase (see Figure 3):


Figure 3. The Change Case portlet

We'll start by looking at the portlet.xml file, shown in Listing 3. The portlet.xml file is a descriptor file that contains configuration details about the bundled portlet(s) in your WAR file.


Listing 3. The portlet.xml 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" 
   id="com.ibm.changecase.ChangeCasePortlet">
   <portlet>
      <portlet-name>ChangeCase</portlet-name>
      <display-name>Change Case Portlet</display-name>
      <portlet-class>com.ibm.changecase.ChangeCasePortlet</portlet-class>
      <supports>
         <mime-type>text/html</mime-type>
         <portlet-mode>view</portlet-mode>
      </supports>
      <portlet-info>
         <title>ChangeCasePortlet</title>
      </portlet-info>
   </portlet>
</portlet-app>

The <portlet-app> tag in Listing 3 defines the XML schema definition and ID for a portlet application. A portlet application can contain zero or more portlets. You use <portlet> tags to define the individual portlets within the portlet application:

  • <portlet-name> - Provides a name that can be used internally or programmatically to reference the portlet.
  • <display-name> - A short name of the portlet, used to display the portlet name in GUI tools that vary by portal container.
  • <portlet-class> - The class that acts as the controller for the portlet.
  • <supports> - These tags define the portlet modes and mime types that the portlet will support.
  • <title> - You can define the portlet's preferred title within portlet.xml. However, how that title will be used is up to the portlet container.

Listing 4 shows the com.ibm.changecase.ChangeCasePortlet portlet class referenced in portlet.xml. This class must implement the javax.portlet.Portlet interface, but fortunately, you don't need to implement the Portlet interface directly. JSR 168 defines a default implementation for the javax.portlet.Portlet interface called the javax.portlet.GenericPortlet class. The com.ibm.changecase.ChangeCasePortlet class extends the GenericPortlet class.


Listing 4. The ChangeCasePortlet class

package com.ibm.changecase;

import java.io.*;
import javax.portlet.*;

/**
 *
 * A sample portlet based on GenericPortlet
 * 
 */
public class ChangeCasePortlet extends GenericPortlet {
   
   private static String VIEW_JSP = "/view.jsp";

   protected void doView(RenderRequest request, RenderResponse response) 
      throws PortletException, IOException {
      response.setContentType(request.getResponseContentType());
       PortletContext context = getPortletConfig().getPortletContext();
       context.getRequestDispatcher(VIEW_JSP).include(request, response);
   }

public void processAction(ActionRequest request, ActionResponse response) 
   throws PortletException, java.io.IOException {
//Do Action Handling here.

}

}

Notice the choice to override the doView() and processAction() methods. The processAction() method is called any time that a portlet action occurs. The doView() method is called when the user is in the portlet's view mode. JSR 168 supports other modes, such as help mode and edit mode. However, if you refer back to Listing 3, you can see in the <supports> section that this portlet supports only the view mode.

Now take a closer look at the doView() method in Listing 4. The model-view-controller (MVC) design pattern is frequently used in portlet coding, as it is in Java servlet coding. Accordingly, in your portlet, the rendering responsibilities are handed off to view.jsp. Alternatively, you could implement the view in the doView() method using prinltn logic:

response.getWriter().println("<p>Hello World</p>()");

The problem with this approach is that the designer of your graphical user interface would need to have knowledge of portlet technology to write the doView() method. JSP developers are decoupled from the intricacies of Java development and can focus on the development of their front-end interfaces. Listing 5 shows view.jsp:


Listing 5. view.jsp

<%@ taglib uri="http://java.sun.com/portlet" prefix="portlet"%>
<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
	pageEncoding="ISO-8859-1" session="false"%>
<portlet:defineObjects />

<%String textBox = renderRequest.getParameter("textBox");
		if (textBox == null)
			textBox = "";
		String caseString = renderRequest.getParameter("case");
		boolean isUpperCase = true;
		if ((caseString != null) && (caseString.equals("false"))) {
			isUpperCase = false;
		}
		String errorMessage = renderRequest.getParameter("errorMessage");%>

<%if (errorMessage != null) {%>
<p><%=errorMessage%></p>
<%}%>

<FORM name="<portlet:namespace/>caseform" action="<portlet:actionURL/>">
<INPUT type="text" name="textBox" size="20" value="<%=textBox%>">
<p><INPUT type="radio" name="case" value="lowercase"
	<%if (!isUpperCase) {%> checked="checked" <%}%>>To Lowercase</p>
<p><INPUT type="radio" name="case" value="uppercase"
	<%if (isUpperCase) {%> checked="checked" <%}%>>To Uppercase</p>
<INPUT type="submit" name="<portlet:namespace/>submitCase"
	value="Change Case"></FORM>

First, notice that you define the portlet tag libraries in view.jsp. This is necessary for the JSP parser to recognize your portlet tags. The first portlet tag that you use is <portlet:defineObjects/>. This tag gives you access to the renderRequest, renderResponse, and portletConfig objects. Using the renderRequest object gives you access to the requestParameters. Your portlet class passes values to the view JSP via the request parameters.

Next in your view.jsp, you create a form that sends the form data to the portlet class. To send the form data, you must create an actionURL, which causes the ChangeCasePortlet portlet class's processAction() method to be called. You use the <portlet:actionURL/> tag to create an actionURL. Notice that in view.jsp you set the value of the textbox and the radio button to the value passed back to the JSP by the server. Consequently, view.jsp is responsible for both handling request input and displaying the portlet's response.

Clicking the form's Submit button invokes the portlet's processAction() method, shown in Listing 6. processAction() receives an ActionRequest object from view.jsp as an input.


Listing 6. The processAction method

 public void processAction(ActionRequest request, ActionResponse response) 
    throws PortletException, java.io.IOException {
    String newCase = request.getParameter("case");
    String textBox = request.getParameter("textBox");
    String errorMessage = null;
      
    boolean isUpperCase = true;
    if ((newCase!=null) && (newCase.equals(ChangeCaseConstants.LOWER_CASE)))
       isUpperCase = false;
    else if ((newCase == null) || (newCase==ChangeCaseConstants.UPPER_CASE))
       errorMessage = "Error no case selected!  Select a case.";
    if (textBox !=null) {
       if (isUpperCase)
          textBox = textBox.toUpperCase();
       else 
          textBox = textBox.toLowerCase();
       response.setRenderParameter("textBox", textBox);
    } else 
       errorMessage = "Error, text in the text box is invalid";
    response.setRenderParameter("case", Boolean.toString(isUpperCase));
    if (errorMessage != null) {
       response.setRenderParameter("errorMessage",errorMessage);
    }
   
 }

The ActionRequest object contains the data that was entered into the form. To retrieve the form data, you use the getParameter() method. In the processAction() method, you also perform the business logic, determining if the user wants uppercase or lowercase output. Based on that logic, you change the incoming text to the desired case and send the text back to the user. Data is sent back to the view using the setRenderParameter() method.


Compiling and packaging your JSR 168 portlet

Now that you've developed your portlet, you need to get it into compiled form and package it for deployment to Pluto. First, make sure that portlet-api-1.0.jar is in your CLASSPATH. Then use the javac compiler to compile ChangeCaseConstants.java and ChangeCasePortlet.java:

javac ChangeCaseConstants.java
javac ChangeCasePortlet.java

Next you need to create the required folder structure for your WAR file, which is the archive by means of which you deploy portlets to a portlet container. Place the two classes you just compiled in the classes\com\ibm\changecase directory.

To build your WAR file, you want the following directory structure, shown in Listing 7:


Listing 7. Directory structure for deployment

changeCaseWAR\
   META-INF
      MANIFEST.MF
   WEB-INF
      classes
         com
            ibm
               changecase
                  ChangeCaseConstants.class
                  ChangeCasePortlet.class
      lib
      tld
         portlet.tld
      portlet.xml
      web.xml
   index.html
   view.jsp

Note that Listing 7 introduces four files we haven't covered yet:

  • portlet.tld: This is the portlet tag library. If you recall, you used the portlet tag library throughout your JSP with references such as <portlet:defineObjects />. The portlet tag library is available in the Apache-SVN repository (see Resources).

  • MANIFEST.MF: Because there are no external dependencies, this manifest file contains nothing except Manifest-Version: 1.0.

  • index.html: If for some reason the context root is accessed directly, index.html is displayed. You can have any properly formed HTML in your index.html.

  • web.xml (shown in Listing 8): This defines the Web application that contains your individual portlet.

Listing 8. web.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" 
   "http://java.sun.com/dtd/web-app_2_3.dtd">
<web-app id="WebApp_ID">
   <display-name>CasePortlet</display-name>
   <welcome-file-list>
      <welcome-file>index.html</welcome-file>
   </welcome-file-list>
   <taglib>
      <taglib-uri>http://java.sun.com/portlet</taglib-uri>
      <taglib-location>tld/portlet.tld</taglib-location>
   </taglib>
   <taglib id="PortletTLD">
      <taglib-uri>http://java.sun.com/portlet</taglib-uri>
      <taglib-location>/WEB-INF/tld/std-portlet.tld</taglib-location>
   </taglib>
</web-app>

Once you've generated MANIFEST.MF, portlet.tld, web.xml, and index.html, you can use the JAR utility to archive the structure shown in Listing 7 into one WAR file:

C:\temp>jar -cvf changeCase.war

The result is a file called changeCase.war, ready for deployment to a JSR 168-compliant portal.


Making sure your portlet is JSR 168-compliant

Now you'll use Apache Pluto to see if your portlet passes the litmus test of JSR168 compliance.

Make sure Apache Pluto is up and running and navigate to the Pluto home page (http://localhost:8080/pluto/portal). Click Admin in the sidebar. You should see the Deploy War portlet displayed on the admin page, as shown in Figure 4. Click Browse and navigate to the location of the changeCase.war file you put together in the previous section and then click Submit.


Figure 4. Pluto's Deploy War portlet

Now you must enter the layout information for the portlet application -- a rather trivial task because you have only one portlet in your portlet application. As you can see in Figure 5, you tell Pluto the portlet has one row and one column and then click Submit to submit this choice to the server:


Figure 5. Entering page-layout information for the portlet application

Next, you must define where in the portlet application's page layout your portlet will appear. You do this by mapping all the portlets in the portlet application to the rows and columns that you just defined. Because you have only one portlet to deploy and you chose earlier to have a page layout with one row and one column, enter the ChangeCase portlet at that location and click Submit, as shown in Figure 6:


Figure 6. Mapping the portlet location

To deploy the portlet, you have the option of either restarting Pluto or hot deploying the portlet application containing the portlet, as shown in Figure 7:


Figure 7. Hot deploying the portlet

A link appears on the sidebar with the name of the portlet application (Change Case). Click that hyperlink. You'll now see the portlet application, with the portlet contained inside it, as shown in Figure 8. At this point you should interact with the Change Case portlet and make sure that it functions as expected. If it does, you can rest assured that this portlet is compliant with JSR 168.


Figure 8. The Change Case portlet deployed to Pluto

The Change Case Portlet will work in any Portal container that supports the JSR 168 portlet standard.


Conclusion

Can I use Pluto in my production environment?

Apache Pluto is suitable only as a test bed for JSR 168-compliance and is not recommended for use in production environments. For production, you should consider a more scalable container. The Apache Software Foundation has an open source portal container named Jetspeed that you can consider (see Resources). WebSphere Portal Server Version 5.1 from IBM is a commercial solution that also supports the JSR 168 standard (see Resources).

Apache Pluto lets portlet developers be certain that their portlets will run in any JSR 168-compliant portal container. Most portal containers, including WebSphere Portal Server, include extended offerings that Portlet Specification doesn't address. For example, IBM WebSphere Portal Server offers the nonstandard click-to-action extensions (cooperative portlets). Whether or not to use the extensions is a judgment call by the enterprise using the portal technologies. As a developer, you should keep in mind that you compromise the portability of your portlets by leveraging such technologies -- but sometimes doing so meets business needs. Apache Pluto lets an organization using portlets know how much they deviate from the Portlet Specification and decide if any steps should be taken to align those portlets with the standard.

The future: JSR 286

JSR 168 went a long way toward bringing order to the portal arena. However, the work of portlet standardization isn't stagnant. The Java Portlet API version 2.0 specification (JSR 286), still in development when this article was written, aims to bring J2EE 1.4 support into the portlet specification (see Resources). Portlet technologies that many vendors addressed with their own implementations in a nonstandard way (portlet filters and formalized inter-portlet communication, to mention a couple) will now make their way into the 2.0 specification. Future versions of Apache Pluto will act as the reference implementation of the JSR 286 specification. When JSR 286 becomes the de facto portlet standard, you'll still be able to use Pluto to test for compliance.

At the time we wrote this article, the alpha release of Pluto 1.1 was not available. Pluto 1.1 will have a new container architecture and include some changes that will make portlet development easier. However, Pluto 1.0.1 will still be a good tool for verifying that your portlets are JSR 168-compliant.



Download

DescriptionNameSizeDownload method
Sample codej-plutoJSR168.war8KBHTTP

Information about download methods


Resources

Learn

Get products and technologies

About the authors

Kulvir Singh Bhogal

Kulvir Singh Bhogal works as an IBM Software Services for WebSphere consultant, devising and implementing J2EE solutions at customer sites across the United States.

Mark Talbot photo

Mark Talbot works for IBM's Industry Solutions, developing applications for the financial sector. You can reach Mark at talbotm@us.ibm.com.

Report abuse help

Report abuse

Thank you. This entry has been flagged for moderator attention.


Report abuse help

Report abuse

Report abuse submission failed. Please try again later.


developerWorks: Sign in


Need an IBM ID?
Forgot your IBM ID?


Forgot your password?
Change your password

By clicking Submit, you agree to the developerWorks terms of use.

 


The first time you sign into developerWorks, a profile is created for you. Select information in your profile (name, country/region, and company) is displayed to the public and will accompany any content you post. You may update your IBM account at any time.

Choose your display name

The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerWorks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

(Must be between 3 – 31 characters.)

By clicking Submit, you agree to the developerWorks terms of use.

 


Rate this article

Comments

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=Java technology, WebSphere
ArticleID=109565
ArticleTitle=Build and test JSR 168-compliant portlets with Apache Pluto
publish-date=04252006