Federated Portals Guide

     Previous  Next    Open TOC in new window    View as PDF - New Window  Get Adobe Reader - New Window
Content starts here

The Interceptor Framework

The Interceptor Framework is a consumer-side framework that lets you programmatically intercept and modify markup and user interaction-related WSRP messages sent to and received from producers. This framework exposes a set of interfaces that you can implement. These interfaces let you examine the content of a WSRP message and take specific action based on that content. For example, if a producer sends a registration error back to the consumer, an interceptor can detect that error and display an informative message to the user or, perhaps, automatically return the information required to complete the registration.

This chapter includes the following topics:

 


Introduction

As Figure 10-1 illustrates, interceptors are implemented in the consumer. They intercept and allow processing of incoming and outgoing WSRP messages passed between the consumer and one or more producers. Interceptors are associated with specific consumer web applications (web application scoped). You can also group together several interceptors to accommodate more complex use cases.

Figure 10-1 Interceptors Run in Consumer Applications

Interceptors Run in Consumer Applications

The interceptor framework defines five public interceptor interfaces. To work with interceptors, you implement one or more of these interfaces and register your implementation classes in a configuration file called wsrp-consumer-handler-config.xml. This configuration file is web application-scoped, and resides in the consumer web application’s WEB-INF directory. See Configuring Interceptors for more information on the configuration file.

To work with interceptors effectively, you must be familiar with basic WSRP operations, such as getMarkup and performBlockingInteraction. You need to understand the purpose of these operations and how they fit into the life cycle of proxy portlets. See Designing Interceptors.

The rest of this chapter explains how to use these interfaces and includes detailed examples and use cases.

 


Use Cases

If you are a consumer-side developer, you can use the Interceptor Framework for many different purposes. Some of the most common use cases for interceptors include:

 


Basic Steps

This section lists the basic steps involved in creating an interceptor. More detailed information on each step is available in the other sections of this chapter. The basic steps include:

 


Designing Interceptors

When designing interceptors, you must first decide what kind of work you want to perform. Depending on the task, you can implement one or more of the interfaces. Each interface is designed to handle a particular type of WSRP operation. For instance, if you are interested in intercepting form data before it is sent to a producer, you might choose to implement the IBlockingInteractionInterceptor. If you are handling registration faults, then you might implement all of the interfaces.

Interceptors are designed to handle the following types of WSRP operations. These operations are wrapped in SOAP messages that are passed between consumers and producers using WSRP:

To use interceptors effectively, you need to be familiar with the purpose of these operations and how they relate to the life cycle of a proxy portlet. For instance, performBlockingInteraction requests are sent when a user submits form data in a portlet.

Tip: If you are interested in learning more about WSRP and the preceding types of WSRP operations, see Inside WSRP (on the dev2dev web site). For a more general overview, see Federated Portal Architecture.

When designing interceptors, also think about the number of interceptors you need to accomplish your work. You can associate more than one interceptor with a producer by creating a group of interceptors. A group is subject to specific rules that govern the order in which methods are executed. For more information see Order of Method Execution.

Tip: Because every request might not have the same data available, it is important to add proper null-condition checks and take appropriate action if data is missing.

 


Interceptor Interfaces

This section describes the five public interceptor interfaces, their methods, method return values, and the context objects that are accessible to the interface methods. This section includes these topics:

Context Objects

The interceptor methods receive context objects that you can use to get and set values in the intercepted SOAP messages. The context object created for each type of interceptor varies depending on the WSRP operation it represents. For instance, the initCookie context object does not contain the same information as the context object for the handleEvents operation. For detailed information on these objects, refer to the Javadoc for the interceptor interfaces. This section describes the flow in which request and response context objects are created and used by interceptors.

Before a message is sent to a producer, or after it is received, the interceptor framework creates an appropriate context object that is passed to the interceptor methods. This object wraps certain elements related to the message. Using methods of the context object, the interceptor can retrieve and set these elements. For example, when a user clicks a link in a remote portlet, the interceptor framework creates a request context object which it then passes to the preInvoke() method of the interceptors. After passing through the interceptors and possibly being modified, the request object is used to construct a message that is sent to the producer. Likewise, the interceptor framework constructs a response context object from an incoming message and passes the object the appropriate interceptor methods.

As illustrated in Figure 10-2, a request context is passed to the preInvoke() methods of registered interceptors. The request context contains information related to the portlet. After processing by one or more interceptors, the interceptor framework creates a message. This message includes any modifications made by the preInvoke() method.

Figure 10-2 Handling a Request Context Object

Handling a Request Context Object

Similarly, as shown in Figure 10-3, the response context object created from an incoming message is passed to the postInvoke() method the interceptors that are associated with the producer that generated the response.

Figure 10-3 Handling a Response Context Object

Handling a Response Context Object

Finally, as shown in Figure 10-4, the response context object created from an incoming error or fault message is passed to either the onFault() or onIOFailure() method. Note that in the case of an onIOFailure, a response SOAP message might not be generated.

Figure 10-4 Handling an Error or Fault

Handling an Error or Fault

Interfaces

The five public interceptor interfaces are summarized in Table 10-1. These interfaces are in the com.bea.wsrp.consumer.interceptor package. Javadoc is available for these interfaces.

Table 10-1 Interceptor Interfaces
Interface
Description
IGetMarkupInterceptor
Allows you to intercept and modify a message that is being sent in a getMarkup message or received in a getMarkupResponse.
IInitCookieInterceptor
Allows you to intercept the initCookie request. This request is made the first time a consumer displays a proxy portlet for a given user. The request allows the producer to initialize cookies and return them to the consumer.
IBlockingInteractionInterceptor
Allows you to intercept and modify a performBlockingInteraction message.
IHandleEventsInterceptor
Allows you to intercept a handleEvents request or response.
IGetRenderDependenciesInterceptor
Allows you to intercept a getRenderDependencies request or response. Render dependencies include cascading stylesheet (CSS) files and scripts, such as JavaScript files, upon which the proper rendering of the portlet depend. For more information on render dependencies, see the section “Portlet Appearance and Features” in the Portlet Development Guide.

Interface Methods

Each interceptor interface includes the same four methods. Table 10-2 summarizes the interceptor methods and when each method is called. Possible return values for each method are discussed in Interceptor Method Return Values.

Tip: The following table is a general summary only, and does not include method parameters or return values. The specific method signatures depend on the interface in which the method is used. Refer to the Javadoc for a detailed description of each method and its parameters.

Table 10-2 Interceptor Methods
Method
Description
preInvoke()
This method is called before creating a SOAP message to send to the producer. For example, this method is called after a user clicks on a link in a proxy portlet. One use of this method is to intercept a user’s input data to verify that it is complete.
postInvoke()
This method is called after a producer has processed its request and sent a response back to the consumer. This method can be used to intercept and filter the markup returned by the producer.
onFault()
This method is called when the producer returns a fault. This method can be used to examine the error and display an informational message or take another appropriate action.
onIOFailure()
This method is called when the there is an IOException while sending or receiving a message. This method can be used to display an informational message or take another appropriate action.

Interceptor Method Return Values

The following tables list the possible return values for each of the four interceptor methods:

For more information on return values, see How Return Status Affects Execution Order.

Table 10-3 Return Values for preInvoke()
Return Value
Description
Status.PreInvoke.CONTINUE_CHAIN
Indicates normal execution.
Status.PreInvoke.ABORT_CHAIN
Skips calling preInvoke() methods of the subsequent interceptors, but sends the message to the producer.
Status.PreInvoke.SKIP_REQUEST_ABORT_CHAIN
Skips calling preInvoke() methods of the subsequent interceptors and skips sending the request message to the producer.

Table 10-4 Return Values for postInvoke()
Return Value
Description
Status.PostInvoke.CONTINUE_CHAIN
Indicates normal execution.
Status.PostInvoke.ABORT_CHAIN
Skips calling postInvoke() methods of the subsequent interceptors.

Table 10-5 Return Values for onFault()
Return Value
Description
Status.OnFault.CONTINUE_CHAIN
Indicates normal execution. The consumer will handle the fault if rest of the interceptors also return CONTINUE_CHAIN status.
Status.OnFault.ABORT_CHAIN
Skips calling onFault() methods of the subsequent interceptors. The consumer will handle the fault.
Status.OnFault.RETRY
Re-sends the message that caused the fault. The onFault() methods of the subsequent interceptors are not called.
Status.OnFault.HANDLED
Skips calling onFault() methods of the subsequent interceptors and assumes that fault has been consumed by the interceptor. The interceptor is responsible for providing all response data.

Table 10-6 Return Values for OnIOFailure()
Return Value
Description
Status.OnIOFailure.CONTINUE_CHAIN
Indicates normal execution. The consumer will handle the IO failure if the rest of the interceptors also return CONTINUE_CHAIN status.
Status.OnIOFailure.ABORT_CHAIN
Skips calling onIOFailure() methods of the subsequent interceptors. The consumer will handle the fault.
Status.OnIOFailure.RETRY
Re-sends the message that caused the IO failure. The onIOFailure() methods of the subsequent interceptors are not called.
Status.OnIOFailure.HANDLED
Skips calling onIOFailure() methods of the subsequent interceptors and assumes that the IO failure is consumed by the interceptor. The interceptor is responsible for providing all response data.

 


Configuring Interceptors

The interceptors are configured in wsrp-consumer-handler-config.xml, a web application scoped configuration file. This configuration file requires two entries: interceptor and interceptor-group. Both of these entries must be present in the configuration file.

The <interceptor> element specifies the fully qualified interceptor classname and provides an arbitrary, unique name. The interceptor class must also be in the web application’s class path or another accessible classpath, such as a system-defined classpath. Each interceptor specified by an <interceptor> element must be referenced in a group, therefore, you must configure at least one <interceptor-group>.

The <interceptor> element includes the following elements.

The <interceptor-group> element includes the following elements.

For more information on groups, and the order in which methods in groups are called, see Order of Method Execution.

Listing 10-1 shows a simple configuration, including two interceptors and one group.

Listing 10-1 Configuring Interceptors
<interceptor>
    <name>AutoRegisteringInterceptor</name>
    <class-name>myInterceptors.AutoRegistrationInterceptor</class-name>
</interceptor>

<interceptor>
    <name>ErrorMessageCustomizer</name>
    <class-name>myInterceptors.ErrorMessageCustomizer</class-name>
</interceptor>
<interceptor-group>
    <name>Group_1</name>
    <producer-handle>MyProducer</producer-handle>
    <interceptor-name>AutoRegistrationInterceptor</interceptor-name>
    <interceptor-name>ErrorMessageCustomizer</interceptor-name>
</interceptor-group>

 


Order of Method Execution

This section discusses the factors that affect the order of method execution in interceptors and groups of interceptors.

Overview

An interceptor group is a collection of interceptors whose methods are called in a well-defined order. A group can be associated with a specific producer or not associated with any producer. If associated with a single producer, then the interceptors in the group will be called only when requests and responses occur between the consumer and that specific producer. If no producer is associated with a group, then the group’s interceptors are called when communication occurs between the consumer and all producers associated with it. For detailed information on configuring a group, see Configuring Interceptors.

Basic Order Of Execution in a Group

This section describes the order in which interceptor methods are called if all methods return a status value of CONTINUE_CHAIN.

Recall that all interceptors contain four methods: preInvoke(), postInvoke(), onFault(), and onIOFailure(). In an interceptor chain, all of the preInvoke() methods are executed, then the postInvoke() methods, the onFault() methods, and finally the onIOFailure() methods.

Figure 10-5 illustrates the order in which methods in an interceptor chain are called for the following chain definition:

Listing 10-2 Example Interceptor Chain Definition
<interceptor-chain>
    <name>Chain-A</name>
    <producer-handle>myProducer</producer-handle>
    <interceptor-name>Interceptor2</interceptor-name>
    <interceptor-name>Interceptor3</interceptor-name>
    <interceptor-name>Interceptor3</interceptor-name>
    <interceptor-name>Interceptor4</interceptor-name>
</interceptor-chain>

The illustration assumes that all methods return the CONTINUE_CHAIN status. Note that all of the preInvoke() methods are called first in the order in which the interceptors appear in the chain configuration, then the postInvoke() methods are called in the reverse order. After all the postInvoke() methods are called, the onFault() methods are called in the order shown in Figure 10-5. Finally, the onIOFailure() methods are called in the order shown in Figure 10-5. If onFault() or onIOFailure() are called, then postInvoke() is not called.

Figure 10-5 Default Method Order in Interceptor Chains

Default Method Order in Interceptor Chains

Tip: Be aware that you can define interceptors in the configuration file that are associated with specific producers or not associated with any specific producer. An unassociated interceptor does not have a <producer-handle> element defined with it. Unassociated interceptors are always called first for all producer transactions, before the interceptors that are associated with a specific producer are called. Unassociated interceptors are called in the order in which they appear in the configuration file. See Configuring Interceptors for more information.

How Return Status Affects Execution Order

The return status of interceptor methods also affects the order in which interceptor methods are executed. It’s helpful to think of chains of interceptor methods. It’s easier to understand the way interceptor chains work if you think of four separate chains: a preInvoke() chain, a postInvoke() chain, an onFault() chain, and an onIOFailure() chain. If you think of chains this way, it’s easier to understand the effect of return status on the execution of the chain.

Table 10-7 summarizes the possible return values for interceptor methods and how they affect the order of execution in a chain.

Table 10-7 Interceptor Method Return Values
Return Value
Description
CONTINUE_CHAIN
If all methods return a CONTINUE_CHAIN status, interceptors in a chain are executed in order.
ABORT_CHAIN
Skips calling methods of the subsequent interceptors in the chain, but sends the message on to the producer. A use case for ABORT_CHAIN is when you trap a registration error. If the interceptor is able to fix the error, it can then be re-submitted to the producer.
SKIP_REQUEST_ABORT_CHAIN
Skips calling methods of the subsequent interceptors in the chain and skips sending the request message to the producer. A use case for SKIP_REQUEST_ABORT_CHAIN is when the interceptor performs caching. If markup exists in the cache, there may be no reason to perform further processing and return a message to the producer.
HANDLED
Skips calling the fault-handling methods of the subsequent interceptors in the chain and assumes that fault has been consumed by the interceptor. The interceptor is responsible for providing markup data inputstream, in the absence of it will result in rendering “no markup found error” error message in the portlet.
RETRY
Re-sends the message that caused the fault. The fault-handling methods of the subsequent interceptors in the chain are not called. Only one retry is permitted per message.

Note: If ABORT_CHAIN or SKIP_REQUEST_ABORT_CHAIN is returned from preInvoke(), all of the interceptors will still be called, in reverse order, during the postInvoke() phase.

Instance Creation and Reuse

A new instance of an interceptor implementation class is created for every message before calling preInvoke(). This same instance is reused to call postInvoke(), onFault(), and onIOFailure(). This allows you to set and use instance variables within the scope of a request. For a given instance, all methods are called once; however, preInvoke() and postInvoke() can be called one more time if the RETRY status is returned by either onFault() or onIOFailure(). Only one retry is permitted per message.

Example Chains

This section includes several examples that illustrate the flow of method execution in an interceptor chain. Refer to Table 10-7 for details on interceptor return values referred to in these examples.

Figure 10-6 illustrates the flow in an interceptor chain when the preInvoke() method is called on the chain. When a status of ABORT_CHAIN returned, a message is immediately returned to the producer. The preInvoke() methods of subsequent interceptors in the chain are not called.

Figure 10-6 preInvoke() Chain with ABORT_CHAIN Return Value

preInvoke() Chain with ABORT_CHAIN Return Value

Figure 10-7 illustrates another example of the flow in an interceptor chain when the preInvoke() method is called on the chain. When a status of SKIP_REQUEST_ABORT_CHAIN is returned, no message is sent to the producer. The preInvoke() methods of subsequent interceptors in the chain are not called.

Figure 10-7 preInvoke() Chain

preInvoke() Chain

Figure 10-8 illustrates the flow in an interceptor chain when the onFault() method is called on the chain. When a status of RETRY is returned, the same message that caused the failure, with possible modifications inserted by the interceptor, is returned to the producer. The onFault() methods of subsequent interceptors in the chain are not called. Only one retry is permitted. If the same fault is returned, the interceptor framework assumes that the error is handled by the interceptor, and a status of HANDLED is returned.

Figure 10-8 onFault() Chain with RETRY Return Value

onFault() Chain with RETRY Return Value

Figure 10-9 illustrates the flow in an interceptor chain when the onIOFailure() method is called on the chain. In this case, the no message is returned to the producer, and the framework assumes that fault has been consumed by the interceptor. The onIOFailure() methods of subsequent interceptors in the chain are not called. Only one retry is permitted. The second retry is not honored, and the fault or exception is passed to a proxy portlet. If the same fault is returned, the interceptor framework assumes that the error is handled by the interceptor, and a status of HANDLED is returned.

Figure 10-9 onIOFailure() Chain with HANDLED Return Value

onIOFailure() Chain with HANDLED Return Value

 


Implementing an Error-Handling Interceptor

This section illustrates two simple interceptor implementations. The first implements the onFault() method and modifies the error message that is returned to the producer. The second implements onFault() and redirects portlet to display an error page.

This section includes these sections:

Modifying an Error Message

You can use interceptors to retrieve and modify exceptions thrown from the producer. In Listing 10-3, the onFault() method retrieves a Throwable from the response. You can design an onFault() method to examine the exception and take any appropriate action. In this case, the error message is retrieved, modified, and written back to the IGetMarkupResponseContext object. The return status HANDLED has the following effects:

Including an Error JSP Page

In this example, the onFault() method is implemented to include an error JSP page in the portlet.

Listing 10-4 DisplayErrorPage Class
import com.bea.wsrp.consumer.interceptor.IGetMarkupInterceptor;
import com.bea.wsrp.model.markup.IGetMarkupRequestContext;
import com.bea.wsrp.model.markup.IGetMarkupResponseContext;
import com.bea.wsrp.consumer.interceptor.Status;
import weblogic.xml.util.StringInputStream;
import myClasses.MyError;

public class DisplayErrorPage implements IGetMarkupInterceptor
{
    public Status.PreInvoke preInvoke(IGetMarkupRequestContext requestContext)
{
return Status.PreInvoke.CONTINUE_CHAIN;
}

    public Status.PostInvoke postInvoke(IGetMarkupRequestContext
                    requestContext, IGetMarkupResponseContext responseContext)
{

return Status.PostInvoke.CONTINUE_CHAIN;
}

public Status.OnFault onFault(IGetMarkupRequestContext requestContext,
                               IGetMarkupResponseContext responseContext,
                               Throwable t)
{
        try
{
           if (t instanceof MyError) {
    responseContext.render(requestContext.getHttpServletRequest(),
                                   requestContext.getHttpServletResponse(),
                                   "/redirectTarget/myTarget.jsp");
            } else {
                responseContext.render(requestContext.getHttpServletRequest(),
                                   requestContext.getHttpServletResponse(),
                                   "/redirectTarget/defaultTarget.jsp");
          }
}
catch (ServletException e)
{
e.printStackTrace();
}
catch (IOException e)
{
e.printStackTrace();
}

return Status.OnFault.HANDLED;
}

public Status.OnIOFailure onIOFailure(IGetMarkupRequestContext
                requestContext, IGetMarkupResponseContext
                responseContext, Throwable t)
{
return Status.OnIOFailure.CONTINUE_CHAIN;
}
}


  Back to Top       Previous  Next