Write a portlet filter

 

Write a portlet filter

 

+

Search Tips   |   Advanced Search

 

The information in this topic applies only to the IBM Portlet API.

A portlet filter is an object that allows information flowing to or from a portlet (or filter) to be intercepted and manipulated. The object being filtered is intentionally left unaware of the filter's presence, allowing it to behave normally. Such an object can either be a portlet or another filter, thus allowing any number of filters to be applied to a single portlet, creating a filter chain (see the illustration below). While portlet filters can be used to manipulate data in any number of ways, one of their primary functions, for example, is to filter a portlet's input and results for use in secondary user interface environments (e.g., text terminals, PDAs, cell phones, and so on.). Because the portlet being filtered does not know about the filter, it can receive and respond to requests in a normal and robust fashion.

Portlet filters allow immense portlet customization without compromising the robustness of the original portlet by encoding specific responses to specific stimuli. Some useful examples of portlet filters include:

  • making a portlet more accessible to disabled users by modifying its original HTML format to make it more compatible with standard screen-reading devices;

  • preparing portlet data for wireless devices by translating original HTML output into WML (wireless markup language); and

  • hiding sensitive data produced by a portlet based on the type of user currently viewing it.

Portlet filters can also be implemented to compress or encrypt data before they are delivered back to the client (and expand or decrypt client responses before they are passed to the portlet). You might also decide to make the portlets more accessible for people with disabilities by having a portlet filter set up to look for screen reading clients like JAWS. When particular client software visits the page, the filter can both receive client input and return portlet output specific to that software's needs. For that matter, a portlet filter can be set up to look for specific clients (based on Portal user information) or Internet addresses, so that data can be tailored to a person's general region, specific location, or even specific personal needs.

Furthermore, portlet filters have a high level of reusability. A portlet filter that takes in HTML data and converts them to more compliant XHTML data or wireless-friendly WML can be used for any number of portlets across an entire site. Instead of embedding such smart transformations and responses in the code of each portlet, a well-written portlet filter allows any portlet to react and respond properly to any number of clients and inputs.

 

The PortletFilter Interface and Classes

The following interface and its classes are located in the com.ibm.wps.pe.pc.legacy.cmpf package and have been made available for development of portlet filters. A more extensive listing of the contents of the entire package is available in the Javadoc.

  • The PortletFilter interface is the means of instantiating and subsequently using a portlet filter. This interface is created to listen for client and/or portlet data being passed back and forth so that the actions of the portlet filter can be invoked when needed.

  • The PortletFilterAdapter class allows us to invoke the portlet filters. It is the default implementation for the PortletFilter interface and includes methods like doFilter() (which calls a particular filtering action), doLogin() (which allows the filter to handle a LOGIN method), and doWindowEvent() (which allows the filter to handle a WINDOWEVENT method).

  • The PortletFilterConfig interface allows the portlet container to examine the portlet to determine its name, parameters, and context.

  • The PortletRequestWrapper and PortletResponseWrapper classes allow the portlet filter to manage portlet requests and responses by wrapping them before passing them to the next object in the chain.

  • The ClientWrapper class allows the filter to determine the capabilities of the client, including its name, preferred markup type, and its capabilities.

 

A Portlet Filter Example

The following example buffers incoming portlet content and writes it out to the user interface without manipulating the incoming data.

Initialize the portlet filter

First do some basic setup, including the importing of some standard java packages for use in the filter. The important package for portlet filtering is com.ibm.wps.pe.pc.legacy.cmpf.

Figure 2. Import packages for portlet filters

package example.myFilter // wps package import com.ibm.wps.pe.pc.legacy.cmpf.*;   // WPS 5.0

// java packages import javax.servlet.*;
import javax.servlet.http.*;
import java.io.IOException;
import java.util.*;
import java.io.*;

/**
 * This class is a filter that creates a PortletResponseWrapper, 
 * intercepts outputstream of the JSP, (optionally) parses it 
 * and delivers the data to the browser. 
 */

Create a new class which extends the PortletFilterAdapter class. Also create two streams, an input for the filter and an output to pass to the next object in the filter chain. (

if there are no other filters in the chain, the output is passed to the Portal itself for writing back to the user interface.) Finally, set up the tracing variable watch for errors in the JSP and set up the init() function which initializes the portlet filter by utilizing the PortletFilterConfig method and values specified in the PortletFilterService properties file. (For more information on how to configure these and other portlet properties, see Portlet configuration.)

Figure 3. PortletFilterAdapter class

  public class myFilter extends PortletFilterAdapter 
  {
  public boolean traceOn=true;   // true allows the viewing of 
                                 // the trace in the constructor                                  // false requires a read at init() 
                                 // time before trace is printed 
  public myFilter() 
  {
    super();
    String methodName="constructor()";
    if(traceOn) 
    {
      // this can never be ON because init() 
      // must set the tracing!
      System.out.println(methodName+"  constructor called");
      System.out.flush();
    }
  }

  public void init(PortletFilterConfig filterConfig) 
              throws PortletException 
  {
    super.init(filterConfig);
    String methodName="init()";

    // get the value of 'MyFilter.traceOn' from 
    // shared\app\config\services\PortletFilterServices.properties     String traceOnString   = filterConfig.getInitParameter("traceOn");

    if(traceOnString.equalsIgnoreCase("1")) 
    {
      traceOn=true;
    } else 
    {
      traceOn=false;
    }

    if(traceOn) 
    {
      System.out.println(methodName+" init called and traceOn=["+traceOn+"]");
      System.out.flush();
    }

    System.out.println("myFilter initialized");
    System.out.flush();
}

Set up the doService method to apply the filter

This is the main section of the filter. Here the doService() method is used to capture the incoming data request, apply a filter to it, then pass the result to the next object in the chain. The first part of this method uses the PrintWriter object to create the byteArrayOS variable of type byteArrayOutputStream, with a 4KB buffer to which the filtered data is written.

Figure 4. doService() method applying the portlet filter

    /**
     * Called by the portlet container (via the doFilter 
   * method) to allow a portlet filter to handle a SERVICE method. 
     * 
     * @param request  the request to pass along the chain.
     * @param response the response to pass along the chain.
     * @param chain    the portlet filter chain      * @exception PortletException      *           if the filter has trouble fulfilling the request      * @exception IOException      *           if the streaming causes an I/O problem      * @see PortletFilterChain      */

    public void doService(PortletRequest request,
                PortletResponse response,
                PortletFilterChain filterChain)
        throws PortletException, IOException     
    {
        //super.doService(request, response, chain);
        String methodName="doService()";
        if(traceOn) 
        {
            System.out.println(methodName+"  -- entering");
            System.out.flush();
        }

        PrintWriter pw = response.getWriter();

        final ByteArrayOutputStream byteArrayOS = 
                           new ByteArrayOutputStream(4096);

        final PrintWriter wrapperWriter = new PrintWriter(byteArrayOS, true);
        filterChain.doFilter (request,new PortletResponseWrapper(response)
        {
            public void flushBuffer() 
            {
                wrapperWriter.flush();
            }

            public PrintWriter getWriter() 
            {
                return(wrapperWriter);
            }
        } 
        );

        // PrintWriter requires a "flush" action in order to 
    // print the current buffer to the screen.
        wrapperWriter.flush();

Write out the result

At this point the portlet can filter the data using whatever methods are appropriate. For example, the portlet could parse the input code, format it for the filter to manage, pass it to other internal or external filter functions, and then write it back out to the portlet chain. In the example below, HTML has been added to the PrintWriter pw indicating the location of the trace file and a <hr> heading to give the client a visual indication that a portlet filter is being used.

Figure 5. Provide filter results in the output

         // Our particular filter functions and processes go here.

        String fileD=System.getProperty("file.separator");
        if(traceOn) 
        {
            pw.write( "<p>Trace is turned ON for this filter and the trace output is ");
        } else 
        {
            pw.write( "<p>Trace is turned OFF for this filter and 
                                        the trace output would be ");
        }
        pw.write( " in <b><wps>"+fileD+"log"+fileD+"SystemOut.log</b>.");
        
        printMiniHeading(pw,response);
        pw.flush();
        
        if(traceOn) 
        {
            System.out.println(methodName+" -- leaving");
            System.out.flush();
        }
    }

The printMiniHeading method writes out very simple HTML dividers that could be used to provide the client with a visual indication that a portlet filter is being used. Any HTML formatting valid for portlets can be used here.

Figure 6. Filter output heading

    /**
     * Called by this class to print the miniature heading so that the      * developer recognizes that their portlet has a filter on it      * @param pw  the PrintWriter to write to      * @param response  the PortletResponse so the filter can print a title      */

    void printMiniHeading(PrintWriter pw, PortletResponse response) 
    {
        String portletTitle = response.encodeNamespace("Portlet");
        pw.write( "<hr>" );
        pw.write( "myFilter for " + portletTitle+"." );
        pw.write( "<hr>" );
    }

The doTitle method allows the portlet filter to manage a DOTITLE method in the request or response. It allows the title information to be accepted by the filter from the request, to be managed (and possibly manipulated) by the filter, then passed in the result to the next object in the filter chain.

Figure 7. doTitle() method implementation

    /**
     * Called by the portlet container (via the doFilter method) to 
     * allow a portlet filter to handle a DOTITLE method. 
     * 
     * @param request  the request to pass along the chain.
     * @param response the response to pass along the chain.
     * @param chain    the portlet filter chain      * @exception PortletException      *                   if the filter has trouble fulfilling the request      * @exception IOException      *                   if the streaming causes an I/O problem      * @see PortletFilterChain      */
    public void doTitle(PortletRequest request,
                PortletResponse response,
                PortletFilterChain chain)
        throws PortletException, IOException     {
        super.doTitle(request, response, chain);
        String methodName="doTitle()";
        if(traceOn) 
        {
            System.out.println(methodName+"  doServiceMethod called");
            System.out.flush();
        }
    }
}