Chapter 13. Reusable logic with portlet filters

This chapter covers

  • Types of portlet filters
  • The portlet filter lifecycle
  • Creating portlet filters
  • Configuring portlet filters

In previous chapters you saw examples where the complete request-processing logic was contained within the lifecycle methods of the portlet. For instance, in the Book Catalog portlet, the logic that sets the title of the portlet window, based on the value of the myaction request parameter, is part of the request-processing logic. Similarly, you can have request-logging logic in lifecycle methods that log requests to a log file, which is later analyzed by a log-analyzer tool to generate important statistics. The logic inside a lifecycle method can’t be used by other portlets, because it’s tightly coupled with the portlet class, so you can’t reuse the logic to programmatically set the portlet title and to log requests.

A portlet filter is a reusable component that allows you to write request- and response-processing logic that can be applied to multiple portlets and that can be reused in different portlet applications with just a few configuration steps. A portlet filter is similar to a servlet filter, and it’s responsible for preprocessing requests before they’re handled by the portlet and for postprocessing responses before they’re sent to the portal server.

In this chapter, we’ll look at different types of portlet filters, their lifecycles, implementation, configuration, and how they can be used individually or in combination with other portlet filter types. We’ll also see how portlet filters can be used by the Book Catalog portlet to dynamically set the portlet title and to convert the title of a book into a hyperlink pointing to a Wikipedia page related to the subject covered in the book. By the end of this chapter, you’ll understand how portlet filters are typically used to preprocess requests and post-process responses, and how they can be used together to create a filter chain.

13.1. Types of portlet filters

In this section, we’ll look at various types of filter interfaces that you can implement to create portlet filters. You saw in chapter 2 that different request and response object types are available to a portlet, depending upon the request-processing phase. Because portlets have multiple request-processing phases, and each phase uses different request and response objects, portlets have a different filter type for each phase.

The functionality of portlet filters is similar to that of Spring interceptors (discussed in chapter 8) and to AOP before and after advice combinations (see chapter 9) which preprocess portlet requests and post-process portlet responses. You can correlate the functionality of a portlet filter to that of a security guard who records entry and exit times of the people entering or leaving a building.

Table 13.1 describes the interfaces provided by the Portlet 2.0 API for creating filters specific to a phase.

Table 13.1. Filter interfaces defined in Portlet 2.0

Filter interface

Description

ActionFilter Filter for preprocessing action requests sent to the portlet (before the invocation of the processAction method) and for postprocessing the response received from the portlet (after processAction returns)
RenderFilter Filter for preprocessing render requests sent to the portlet (before the invocation of the render method) and for postprocessing the response received from the portlet (after render returns)
ResourceFilter Filter for preprocessing resource requests sent to the portlet (before the invocation of the serveResource method) and for postprocessing the response received from the portlet (after serveResource returns)
EventFilter Filter for preprocessing event requests sent to the portlet (before the invocation of the processEvent method) and for postprocessing the response received from the portlet (after processEvent returns)

You’ll choose the interface that’s appropriate for creating a filter that meets your requirements. For instance, if you only need to preprocess render requests and post-process render responses, then you only need to create a filter that implements the RenderFilter interface.

 

Note

Your filter implementation class can implement multiple filter interfaces if your filter applies to multiple lifecycle phases of the portlet.

 

Let’s now look at the methods defined in the portlet filter interfaces and their lifecycle.

13.2. Portlet filter interface methods and lifecycle

The PortletFilter interface defines methods for managing the lifecycle of a portlet filter. In this section, we’ll look at the methods defined by filter interfaces and the PortletFilter interface, and at when these methods are invoked by the portlet container to manage the lifecycle of the portlet filter.

13.2.1. Portlet filter interface methods

Even though there are different filter interfaces, they define similar methods. Figure 13.1 shows that different filter interfaces inherit from the PortletFilter interface. This figure shows that the PortletFilter interface is the superinterface of the other filter interfaces. PortletFilter defines the init and destroy lifecycle methods, and the filter interfaces define a doFilter method that accepts request and response objects specific to the portlet lifecycle phase they apply to. Table 13.2 describes the purpose of each of the methods defined in the base PortletFilter interface and in the interfaces specific to the portlet lifecycle phases.

Figure 13.1. The filter interfaces that apply to the different lifecycle methods of a portlet. PortletFilter defines init and destroy methods, and each subinterface defines a doFilter method.

Table 13.2. Filter methods

Method

Description

init(FilterConfig config) Invoked by the portlet container before the filter is made available for filtering requests and responses. In this method, the filter initializes the resources that it needs to filter requests and responses.
Destroy Invoked by the portlet container to inform the filter that it is being removed from service. In this method, the filter releases the resources that are being held by the filter instance. If the filter holds any persistent information, that information is persisted in the destroy method.
doFilter Invoked when the portlet request is passed to the filter. Each filter interface has a different doFilter method, depending upon the lifecycle phase to which the filter applies.

The signature of init method is as follows:

void init(FilterConfig filterConfig) throws PortletException

The FilterConfig object, passed to the init method, is used to access the filter initialization parameters and the PortletContext associated with the portlet application in which the filter is deployed. You’ll see later in this chapter how the initialization parameters are specified for portlet filters in the portlet deployment descriptor.

The doFilter method signature varies from one filter interface to another because different request and response objects are available to a filter in different portlet lifecycle phases. For instance, RenderFilter defines the doFilter method like this:

void doFilter(RenderRequest request, RenderResponse response,
     FilterChain chain) throws IOException, PortletException

The ActionFilter interface defines the doFilter method as follows:

void doFilter(ActionRequest request, ActionResponse response,
     FilterChain chain) throws IOException, PortletException

As you can see, the RenderFilter interface’s doFilter method accepts RenderRequest and RenderResponse objects, whereas the ActionFilter interface’s doFilter method accepts ActionRequest and ActionResponse objects.

The FilterChain object is provided by the portlet container, and it represents the filter chain that applies to the portlet request. It’s used to pass portlet requests to the next filter in the chain or to the target portlet lifecycle method.

Now that you know the methods that you need to implement to create a portlet filter, let’s look at how the filter lifecycle is managed by the portlet container.

13.2.2. Portlet filter lifecycle

Figure 13.2 shows the portlet filter lifecycle, which begins with the call to the init method and ends with the destroy method.

Figure 13.2. The portlet filter lifecycle. The portlet filter does the preprocessing of the request or the postprocessing of the response. FilterChain passes the request to the next filter in the chain, or to the target portlet if the filter is the last filter in the chain.

When a portlet application is deployed, the portlet container identifies the portlet filters that apply to the portlet and creates a FilterChain object. The portlet request is received for the portlet. The portlet container invokes the doFilter method of the first filter in the FilterChain , passing the request and response objects and the FilterChain object.

The portlet filter preprocesses the portlet request, which may include creating wrapped request or response objects. For instance, in the case of RenderFilter, you may create a RenderRequestWrapper or RenderResponseWrapper object to be passed down the FilterChain.

The filter invokes the FilterChain’s doFilter method, passing the original (or wrapped) request and response objects and the FilterChain object. FilterChain is responsible for invoking the doFilter method of the next filter in the chain, or the lifecycle method of the portlet if the filter is the last filter in the chain.

The lifecycle method of the portlet is invoked after the last filter in the chain is invoked. The response generated by the portlet is postprocessed. For instance, in the case of RenderFilter, you may set the title of the portlet window or write additional data to the response. A response is sent by the portlet container to the portal server.

Figure 13.2 shows that a filter’s init and destroy methods are invoked by the portlet container at appropriate times to indicate that the filter is being put into or taken out of service. A portlet request flows through the filter chain and finally invokes the lifecycle method of the target portlet.

It’s important for a filter to invoke the FilterChain’s doFilter method to pass the request to the next filter in the chain, or to the target portlet in case the filter is the last filter in the chain; if it doesn’t, that indicates that the filter no longer wants to continue processing the request, and that the filter itself is responsible for generating the response. For instance, an error filter may check for the existence of a request attribute that indicates whether the processing of a previous filter resulted in an error. If the request attribute is found, the error filter stops processing of the request—it doesn’t invoke the doFilter method and instead generates the response itself.

Before we delve into the details of writing and configuring portlet filters, let’s first look at the requirements of the Book Catalog portlet that you’ll address in this chapter using portlet filters.

13.3. Using portlet filters with the Book Catalog portlet

You saw in chapter 4 that you can set the title of a portlet window using the RenderResponse object’s setTitle method. You used the portlet resource bundle, the Language-ext.properties file, to specify portlet titles and programmatically set the title based on the value of the myaction request parameter.

 

Note

If you don’t remember the details, you can refer to the ch3_BookCatalog Eclipse project and see how the Book Catalog portlet made use of titles specified in the resource bundle, the Language-ext.properties file, to dynamically set the title of the portlet.

 

The logic that set the title of the Book Catalog portlet was inside the request-handling methods defined in the BookCatalogPortlet class, making it nonreusable. Dynamically setting the portlet title based on the value of a request parameter is a good candidate for filters because the same logic can be used by different portlets to set their window titles. This brings modularity to the request-processing logic—another advantage of using portlet filters.

You can also use portlet filters to perform checks on the portlet request and response. For instance, the Book Catalog portlet can use a filter to check whether an action request contains a parameter named javax.portlet.action, which identifies the action method of the portlet to be invoked. If no javax.portlet.action parameter is found, it means that the portlet doesn’t make use of the @ProcessAction annotation to identify an action method to be invoked. In this case, a warning message can be displayed on the portlet, specifying that the recently invoked action request didn’t contain the javax.portlet.action parameter. Another check that you can perform using filters is determining whether the action request uses an HTTP POST or HTTP GET method. You should use HTTP POST for action requests because they’re meant to change state on the server.

Because you can use filters to modify responses generated by the portlet, you can use a filter to convert text in the response to hyperlinks. In the Book Catalog portlet, the titles of the books contain the name of the technology (or tool or framework) that the book discusses. You can use a filter to convert the name of the technology in the book title to a hyperlink that opens the official website or Wikipedia page for that technology. For instance, if the title of the book is Portlets in Action, the filter could convert the word “Portlets” in the book title to a hyperlink that refers to the Wikipedia page for portlet technology.

Let’s now look at some examples that demonstrate how to create a portlet filter and configure it in the portlet.xml file.

13.4. Setting the portlet title with the portlet filter

Before you create a filter, you need to first identify the filter interface or interfaces that you must implement to create the filter class. The filter interfaces that you implement will depend on the portlet lifecycle phases to which your filter applies.

For instance, to set the title of a portlet dynamically, your filter must invoke the setTitle method on the RenderResponse object returned by the portlet’s render method. This means your filter class must implement the RenderFilter interface. On the other hand, if you need to check for the existence of the javax.portlet.action request parameter in the action request and display a warning message if it’s not present, you’ll need to implement the ActionFilter interface (to check for the javax.portlet.action parameter) and also the RenderFilter interface (to write the warning message).

 

Code Reference

At this point, you should import the ch13_BookCatalog_Filter project into your Eclipse workspace so you can see how the code listings in the rest of this chapter are used in the Book Catalog portlet.

 

Listing 13.1 shows the PortletTitleFilter filter, which sets the title of the portlet window based on the value of the request parameter whose name is configured as an initialization parameter for the filter. The Book Catalog portlet uses PortletTitleFilter to set the title of the portlet based on the value of the myaction request parameter.

Listing 13.1. PortletTitleFilter dynamically sets the portlet window title.

The PortletTitleFilter filter implements the RenderFilter interface because it’s responsible for postprocessing responses generated by the Book Catalog portlet’s render method.

The FilterConfig object’s getInitParameter method obtains the value of the reqParamName filter initialization parameter . This parameter specifies the name of the request parameter whose value is used to determine the title of the portlet window. In the case of the Book Catalog portlet, the myaction parameter is used as the value of the reqParamName initialization parameter. The title.properties file containing the titles of the portlet is loaded .

The FilterChain object’s doFilter method is invoked , which passes the portlet request to the next filter or to the target portlet. If you need to do any preprocessing of the request, that preprocessing code must be executed before the call to FilterChain’s doFilter method. The portlet title is retrieved from the title.properties file based on the value of the request parameter specified by the reqParamName filter initialization parameter. The portlet title is set using the RenderResponse object’s setTitle method.

To dynamically set the portlet title, PortletTitleFilter uses the following strategy to identify the portlet title in the title.properties file:

  • The portlet title has the following format: portlet.title.<value of reqParamName parameter>, where <value of reqParamName parameter> refers to the value of the request parameter whose name is the value of the reqParamName filter initialization parameter. In the case of the Book Catalog portlet, the value of reqParamName is myaction, so the value of the myaction parameter is used to identify the portlet title in the title.properties file. For instance, if the name of the myaction parameter is addBookForm, the value of the portlet.title.addBookForm property in the title.properties file is set as the title of the Book Catalog portlet.
  • If the portlet title isn’t found in the title.properties file, the value of the portlet.title.default property is used as the portlet title. This situation will arise if the developer forgets to specify a portlet title in the title.properties file or if the request parameter isn’t found in the request.
  • The portlet title in EDIT and HELP portlet modes is identified by the values of the portlet.title.preferences and portlet.title.help properties, respectively.

If you follow this strategy in defining portlet titles in the title.properties file, the PortletTitleFilter filter can be reused by any portlet for setting the portlet title dynamically.

To use a filter, you must also configure it in the portlet.xml file. The next listing shows how you can configure PortletTitleFilter in portlet.xml and map it to the render phase of the Book Catalog portlet.

Listing 13.2. PortletTitleFilter configuration in the portlet.xml file

The Book Catalog portlet is defined. The PortletTitleFilter filter is defined using the <filter> element. It has several subelements:

  • <filter-name>—Specifies a unique name for the filter.
  • <filter-class>—Specifies the fully qualified name of the filter class.
  • <lifecycle>—Specifies the portlet lifecycle phase to which the filter applies. The value RENDER_PHASE indicates that the PortletTitleFilter is applied to the render phase of the portlet to which the filter maps. The value of the <lifecycle> element should be the lifecycle phase supported by the filter class. For instance, PortletTitleFilter doesn’t implement the ActionFilter interface, so it shouldn’t specify ACTION_PHASE as the value of the <lifecycle> element. If a filter applies to multiple lifecycle phases of a portlet, additional <lifecycle> elements are used to specify the lifecycle phases to which the filter applies.
  • <init-param>—Specifies the initialization parameter for the filter , which a filter can obtain using the FilterConfig object. The reqParamName initialization parameter identifies the request parameter that’s used by PortletTitleFilter to dynamically set the portlet title. Because the Book Catalog portlet uses the myaction request parameter to determine the title of the window, myaction is specified as the value of the reqParamName parameter.

The <filter-mapping> element maps the portlet filter to one or more portlets in the same portlet application. It includes these subelements:

  • <filter-name>—Identifies the filter for which this <filter-mapping> element is defined.
  • <portlet-name>—Specifies the portlets to which the filter applies. The value of the <portlet-name> element must match a <portlet-name> subelement of the <portlet> element. You can also use the asterisk (*) wildcard character to map a filter to multiple portlets in the portlet application. For instance, if the value of the <portlet-name> element is specified as book*, the PortletTitleFilter would apply to all portlets whose name starts with book, like bookCatalog, booking, bookShopper, and so on.

 

Warning

If a filter definition specifies a value of <lifecycle> element that is not supported by the filter (meaning that the filter doesn’t implement the corresponding filter interface), the portlet container may ignore that filter or throw an exception during deployment. In the case of Liferay Portal 6.0, the portlet container throws an exception at runtime.

 

Let’s now look at UtilityFilter, which applies to both the render and action lifecycle phases of a portlet.

13.5. Validating requests with portlet filters

The UtilityFilter checks that a portlet’s action method is invoked via the HTTP POST method and that the portlet class makes use of the @ProcessAction annotation to identify an action method. If a portlet uses the @ProcessAction annotation, the action request will contain a parameter named javax.portlet.action.

If UtilityFilter finds that the HTTP method is GET, it displays the following warning message: “WARNING: Action request makes use of GET HTTP method.” If UtilityFilter finds that the javax.portlet.action request parameter isn’t present in the action request, it displays the following warning message: “WARNING: Action request doesn’t contain javax.portlet.action parameter. Are you using annotations?”

Figure 13.3 shows that the warning message is displayed by the Book Catalog portlet when a user removes a book from the catalog.

Figure 13.3. UtilityFilter shows the message, “WARNING: Action request makes use of GET HTTP method” when the action request sent to the Book Catalog portlet uses the HTTP GET method. In the case of the Book Catalog portlet, an HTTP GET is used for the action request that’s sent when a user clicks the Remove hyperlink.

The UtilityFilter checks the incoming ActionRequest and writes a warning message to the RenderResponse object, as shown next.

Listing 13.3. UtilityFilter checks the action request.

The UtilityFilter implements both the ActionFilter and RenderFilter interfaces. If the HTTP method associated with the action request is not POST, a warning message is created. If the request parameter javax.portlet.action doesn’t exist in the action request, an appropriate warning message is created. The warning messages are set in the ActionRequest with an attribute named warningMsg. The warningMsg attribute that was set in the ActionRequest is retrieved and written to the portlet response using the PrintWriter object.

In listing 13.3, because the UtilityFilter needs to share the warningMsg action request attribute with the render request, you must set the actionScopedRequestAttributes container-runtime option to true. Because UtilityFilter implements both the RenderFilter and ActionFilter interfaces and assumes that the doFilter method for the render request is invoked after the doFilter method for the action request, you must configure UtilityFilter to apply to both the RENDER_PHASE and the ACTION_PHASE of the portlet.

So far in this section, we’ve looked at examples where you use one or more filter interfaces and preprocessed portlet requests or postprocessed portlet responses. We’ll now look at an example in which a response wrapper object is used to customize a response generated by the Book Catalog portlet.

13.6. Converting text to hyperlinks with portlet filters

Request and response objects received by a filter’s doFilter method are passed to lower-order filters in the FilterChain and to the lifecycle method of the portlets to which the filter applies. This gives you an opportunity to use portlet request and response wrapper objects to customize the behavior of the request and response objects to perform filtering.

For instance, you can use RenderResponseWrapper and override the getWriter method to return a CharArrayWriter (a subclass of the java.io.Writer class, like the PrintWriter class), which is used by lower-order filters in the filter chain and the target portlet to write response data. Later, the filter can retrieve response data from CharArrayWriter and modify it.

Suppose we wanted the Book Catalog portlet to display the technology identified in the book title as a hyperlink to the official website or Wikipedia page for that technology. For example, figure 13.4 shows that the name of the technology, like AspectJ or ActiveMQ, is shown as a hyperlink; these links open the Wikipedia pages for the relevant technologies.

Figure 13.4. The name of technology in the book title is displayed as a hyperlink. RenderResponseWrapper is used to convert the text to a hyperlink in the response.

 

Note

Figure 13.4 shows the Book Catalog portlet deployed on OpenPortal Portlet Container 2.1.2 with GlassFish Server v3.0.1, because Liferay Portal 6.0 doesn’t allow the modification of response data.

 

To transform the text in the response to a hyperlink, you need to access the response generated by the portlet. Portlet response wrapper objects are used to customize the behavior of methods defined in portlet response objects. For instance, you can use RenderResponseWrapper to override the behavior of the RenderResponse’s getWriter method.

The next listing shows how you can override RenderResponse’s getWriter method to store character data written by a portlet or filter for later use.

Listing 13.4. The CharResponseWrapper class

CharResponseWrapper represents a RenderResponseWrapper object. CharResponseWrapper defines an instance of a java.io.CharArrayWriter object. CharArrayWriter (a subclass of java.io.Writer) stores character data. The CharResponseWrapper constructor creates a new instance of CharArrayWriter. Then CharResponseWrapper overrides RenderResponseWrapper’s getWriter method to return a PrintWriter object that writes the character stream to CharArrayWriter.

In listing 13.4, overriding the getWriter method has an important implication. A portlet calls the RenderResponse object’s getWriter method to write character response data. If you pass CharResponseWrapper, instead of the RenderResponse object, to a portlet, the call to getWriter will return a PrintWriter object that writes the character stream to the CharArrayWriter instance. Because the response data is available in the CharArrayWriter instance variable of CharResponseWrapper, it can be obtained and modified by a portlet filter before sending it to the portal server.

The HyperlinkFilter configuration in the portlet.xml file defines initialization parameters specifying the names of technologies and the hyperlinks to which they should be converted when they’re found in the response, as shown next.

Listing 13.5. HyperlinkFilter configuration in the portlet.xml file

HyperlinkFilter searches the response data for the initialization parameter names and replaces them with hyperlinks specified by the initialization parameter value. The following listing shows how HyperlinkFilter makes use of the CharResponseWrapper to convert names of technologies in book titles to hyperlinks.

Listing 13.6. The HyperlinkFilter class

The name of the filter initialization parameter is added to the searchNames list; the value of the filter initialization parameter is added as an HTML <a> element to the replacements list. We want to search the response data for names in the searchNames list and replace them with elements from the replacements list.

The CharResponseWrapper is created during the preprocessing of the request and it’s passed to the lower-order filters in the chain or to the portlet mapped to HyperlinkFilter. The response postprocessing begins by first retrieving the response data from the CharResponseWrapper instance. All occurrences of searchNames elements in the response data are replaced with the corresponding replacements elements. Because the replacements elements are HTML <a> elements, this effectively converts text matching searchNames elements in the response data to hyperlinks.

Now that you’ve seen examples of developing and configuring portlet filters, you’re ready to see how you can create and configure filter chains.

13.7. Filter chaining

In previous examples, you saw how a single filter performs request and response processing. It’s also possible to define a set of filters that preprocesses requests or postprocesses responses. When multiple filters apply to a request, they’re referred to as a filter chain. Filters are applied to the request in the order in which the <filter-mapping> elements are defined in the portlet.xml file.

Consider the following sequence of <filter-mapping> declarations in the Book Catalog portlet’s portlet.xml file:

<filter-mapping>
 <filter-name>hyperlinkFilter</filter-name>
 <portlet-name>bookCatalog</portlet-name>
</filter-mapping>

<filter-mapping>
 <filter-name>titleFilter</filter-name>
 <portlet-name>bookCatalog</portlet-name>
</filter-mapping>

<filter-mapping>
 <filter-name>utilityFilter</filter-name>
 <portlet-name>bookCatalog</portlet-name>
</filter-mapping>

Because filter mappings for the Book Catalog portlet are declared in the sequence hyperlinkFilter, then titleFilter, then utilityFilter, they’re invoked in the same order when a portlet request is received for the Book Catalog portlet.

It’s important to note that only those filters that apply to the lifecycle phase of the portlet are invoked. For instance, if an action request is received for a portlet, only the filters that apply to ACTION_PHASE are invoked.

 

Note

The request and response objects passed by a filter to the doFilter method are available to the next filter in the chain. If you passed a request or response wrapper object to the doFilter method, it would be available to the next filter in the chain.

 

Filter chaining can be useful when you want the preprocessing of a request or postprocessing of a response to occur in a particular sequence. For instance, you may have a request-logging filter that must be invoked after the security filter has verified that the request comes from an authenticated user.

13.8. Summary

In this chapter, you saw how filters can be created to preprocess different types of portlet requests and post-process different types of portlet responses. We also looked at an example of how portlet response wrapper objects can be used to modify responses generated by portlet filters.

Filter logic is reusable, which makes write-once-use-anywhere possible. Portlet filters bring modularity to your portlet code, so their use is recommended if the processing logic needs to be reused across different portlets or portlet applications.

In the next chapter, we’ll explore the concept of portlet bridges, which make it possible to expose your existing web applications as portlets.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.223.196.146