![]() ![]() ![]() ![]() ![]() ![]() |
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:
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.
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.
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:
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:
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 Oracle Technology Network web sit e. 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. |
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:
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.
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.
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.
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.
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.
|
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. |
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.
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.
name
– A unique name within the scope of a web application.producer-handle
– (Optional) If you specify the handle for a registered producer, the intereceptor(s) in the group will only be called on messages receieved from or sent to that producer. If you do not specify a producer handle, then the interceptor(s) in the group will be called for all producers associated with the consumer. interceptor-name
– The name(s) of the interceptors you want to include in the group. Use the name(s) specified in the interceptor element(s).
The <interceptor-group>
element includes the following elements.
name
– A unique name within the scope of a web application.producer-handle
– (Optional) If you specify the handle for a registered producer, the intereceptor(s) in the group will only be called on messages receieved from or sent to that producer. If you do not specify a producer handle, then the interceptor(s) in the group will be called for all producers associated with the consumer. interceptor-name
– The name(s) of the interceptors you want to include in the group. Use the name(s) specified in the interceptor element(s). 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.
<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>
This section discusses the factors that affect the order of method execution in interceptors and groups of interceptors.
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.
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:
<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.
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. |
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.
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. |
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.
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-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-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-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.
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:
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:
onFault()
methods in the chain. 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;
public class ErrorMessageCustomizer 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)
{
String message = "This Message is Customized by ErrorMessageCustomizer\n";
message = message + t.getMessage();
StringInputStream stringInputStream = new StringInputStream(message);
responseContext.setMarkupData(stringInputStream);
return Status.OnFault.HANDLED;
}
public Status.OnIOFailure onIOFailure(IGetMarkupRequestContext requestContext,
IGetMarkupResponseContext responseContext, Throwable t)
{
return Status.OnIOFailure.CONTINUE_CHAIN;
}
}
In this example, the onFault()
method is implemented to include an error JSP page in the portlet.
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;
}
}
![]() ![]() ![]() |