Writing a portlet filter
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.
Note: The information in this topic applies only to the IBM Portlet API.
Figure 1. Portlet filtering chain
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)
- 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 your
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 you 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. (Note: 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.
Figure 3. PortletFilterAdapter classpublic 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
// Your 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();
}
}
}
Parent topic: Understanding the basics
|
|
|