BEA Logo BEA WebLogic Portal Release 4.0

  BEA Home  |  Events  |  Solutions  |  Partners  |  Products  |  Services  |  Download  |  Developer Center  |  WebSUPPORT

 

   WebLogic Portal Documentation   |   Using Webflow and Pipeline   |   Previous Topic   |   Next Topic   |   Contents   |   Index

Customizing and Extending Webflow

 

Although the applications in the WebLogic Portal product suite build upon a solid Webflow implementation that you can use when building your own applications, the Webflow mechanism has also been designed for easy customization and extensibility. For example, if your organization dictates the use of a new business process, the Java/EJB developers on your project team can utilize the existing Webflow infrastructure to create and incorporate these components into the system. Once created, the new Webflow components can be reused like any of the prebuilt components BEA provides. This topic describes some concepts that will allow you to customize and extend Webflow to meet your specific requirements.

Note: The diagrams in this topic are used primarily to illustrate dependencies in the classes. Please be sure to visit the Javadoc for the most up-to-date information.

This topic includes the following sections:

 


Pipeline Session Internals

Although Pipelines and Pipeline Components are reusable, they must relate to a particular visitor's experience on your Web site to make their execution relevant. For this reason, Pipeline Components always operate on a Pipeline Session. This section provides you with more detailed information about the Pipeline Session, and provides instructions for configuring the Pipeline Session to meet your specific requirements. Specifically, this section includes information about:

Note: It is assumed that you have already read The Pipeline Session. If you have not, it is strongly recommended that you do so before continuing with this section.

Managing the Pipeline Session

The Pipeline Session is an interface containing a number of helpful methods. For detailed information about the Pipeline Session interface, see the Javadoc.

Accessing the PipelineSession Interface

To access the PipelineSession interface from within a JavaServer Page (JSP), use the Pipeline Session JSP tags described in Pipeline Session Tags.

If you need to access the PipelineSession interface from within an Input Processor class (and your Input Processor class extends the InputProcessorSupport class), you can use the static helper methods on the InputProcessorSupport class to access the Pipeline Session. Similarly, if you need to access the PipelineSession interface from within a Pipeline Component class (and your Pipeline Component class extends the PipelineComponentSupport class), you can use the static helper methods on the PipelineComponentSupport class to access the Pipeline Session. See Overview of the InputProcessorSupport Helper Methods or Overview of the PipelineComponentSupport Helper Methods for more information.

Notes: For more information about the static helper methods on the InputProcessorSupport class, see Creating a New Input Processor or the Javadoc. For more information about the static helper methods on the PipelineComponentSupport class, see Creating a New Pipeline Component or the Javadoc.

If your Input Processor class does not extend the InputProcessorSupport class, you can also use the SessionManagerFactory class to access the PipelineSession interface, as shown in the following code fragment:

public Object process(HttpServletRequest req, Object requestContext) throws ProcessingException

{

PipelineSession pSession = null;

pSession = SessionManagerFactory.getSessionManager(), getPipelineSession(req);

...

Note: For more information about the SessionManagerFactory class, see the Javadoc.

Setting and Getting Pipeline Session Properties

To set or get properties in the Pipeline Session from within a JavaServer Page (JSP), use the Pipeline Session JSP tags described in Pipeline Session Tags.

If you need to set or get properties in the Pipeline Session from within an Input Processor or Pipeline Component class (and your class extends the InputProcessorSupport or PipelineComponentSupport class, respectively), you can use the static helper methods provided by these support classes. An alternative is to call the Pipeline Session directly using the getter/setter methods, but if you do so, you will need to handle the InvalidArgumentException exceptions that the Pipeline Session throws. The following sections briefly describe the methods that are made available by the support classes.

Overview of the InputProcessorSupport Helper Methods

public static void setRequestAttribute(String key, Object obj, String namespace, Object reqContext, PipelineSession pSession) throws ProcessingException

public static void setSessionAttribute(String key, Object obj, String namespace, PipelineSession pSession) throws ProcessingException

public static Object getRequestAttribute(String key, String namespace, Object reqContext, PipelineSession pSession) throws ProcessingException

public static Object getSessionAttribute(String key, String namespace, PipelineSession pSession) throws ProcessingException

Notes: More information about these methods can be located in the Javadoc.

The scope of Pipeline Session properties is described in detail in Property Scoping.

Overview of the PipelineComponentSupport Helper Methods

public static void setRequestAttribute(String key, Object obj, String namespace, Object reqContext, PipelineSession pSession) throws PipelineException

public static void setSessionAttribute(String key, Object obj, String namespace, PipelineSession pSession) throws PipelineException

public static Object getRequestAttribute(String key, String namespace, Object reqContext, PipelineSession pSession) throws PipelineException

public static Object getSessionAttribute(String key, String namespace, PipelineSession pSession) throws PipelineException

Notes: More information about these methods can be located in the Javadoc.

The scope of Pipeline Session properties is described in detail in Property Scoping.

Using the Support Classes to Capture Exception Messages

If your Input Processor or Pipeline Component class extends its associated support class, you may also want to use the static helper methods on the InputProcessorSupport and PipelineComponentSupport classes to capture exception messages from the Pipeline Session and throw an exception from your Input Processor or Pipeline Component with the message set accordingly. An example of how to do this is shown in the following code fragment (taken from an Input Processor class):

public Object process(HttpServletRequest req, Object requestContext) throws ProcessingException

{

...

// Put the category ID in the Pipeline Session

setRequestAttribute(CATEGORY_ID, category, namespace, requestContext, pSession);

...

Property Scoping

All properties in the Pipeline Session can have one of two scopes: Pipeline Session scope or Request scope. Pipeline Session and Request scoping differ by how long the property is retained.

Request-Scoped Pipeline Session Properties

When properties are Request-scoped, they are made available in the HTTPServletRequest and exist only for the life of an HTTP request. In other words, Request-scoped properties are available from the time they are set, up to and including the display of the next JSP. The property is automatically deleted when a new request starts. Therefore, Request scope is useful for temporary objects that will only be needed for one page, and is less expensive than Pipeline Session scope. For example, search results from the Product Catalog are stored as Request-scoped properties. Request-scoped properties should be accessed via the <webflow:getProperty> JSP tag or via the appropriate helper method from one of the support classes discussed in Setting and Getting Pipeline Session Properties.

Note: More information about the <webflow:getProperty> JSP tag can be found in Pipeline Session Tags.

Pipeline Session-Scoped Pipeline Session Properties

Properties that must live longer than the HTTP request should be specified as Pipeline Session scope, which will cause them to be retained throughout the Web site visitor's HTTP session, but will be a more expensive operation. If you know that a Pipeline Session property is only required for the current request, use the Request scope. Pipeline Session-scoped properties should be accessed via the <webflow:getProperty> JSP tag or via the appropriate helper method from one of the support classes discussed in Setting and Getting Pipeline Session Properties.

Note: More information about the <webflow:getProperty> JSP tag can be found in Pipeline Session Tags.

Pipeline Session scope is the default scope for Pipeline Session properties, and will be used if the optional scope attribute to the Pipeline Session JSP tags is not specified.

Note: For more information about the support classes' static helper methods for setting and getting Pipeline Session properties, see Setting and Getting Pipeline Session Properties.

Serializing Pipeline Session Properties

All properties added to the Pipeline Session should be serializable. If they are not, the server will generate an error when trying to serialize the Pipeline Session, and thus no Pipelines will be executed. This is especially relevant in clustered and distributed environments. To assist in debugging, uncomment the com.bea.p13n.appflow.pipeline.internal.PipelineExecutorImpl: on line in the debug.properties file by removing the # sign. Then, when one of the static helper methods for setting a Pipeline Session property (attribute) is called, the server console will indicate whether that property is serializable or not.

Note: For more information about the support classes' static helper methods for setting and getting Pipeline Session properties, see Setting and Getting Pipeline Session Properties.

 


Error Handling

You can configure Webflow to handle any type of exception (as well as superclasses of that exception) by creating one or more <namespace>.wf files using the Webflow Editor. To assist you in error handling, this section includes information about:

Non-Runtime and Runtime Processor Exceptions

It is important to understand that runtime exceptions are treated slightly different from non-runtime exceptions. Throughout this explanation, it may be helpful to refer to Figure 4-1, which was first introduced in High-Level Architecture.

Figure 4-1 Webflow High-Level Architecture


 

When a processor (Input Processor processor, Pipeline Processor, or Extension (Custom) Processor) throws an exception, then the Webflow mechanism performs the following steps (in order):

  1. If the exception is a non-runtime exception, Webflow logs the exception at the INFO level, with no stack trace. If the exception is a runtime exception, then Webflow logs the exception at the ERROR level with a stack trace.

  2. Searches for the specific exception in the exception list of the Processor Node. If found, the Webflow invokes that destination.

  3. Searches for a superclass of the exception in the exception list of the Processor Node. If not found, Webflow walks all the way up to the Exception exception in an attempt to find and invoke a destination.

  4. Searches for the specific exception in the exception list of the Wildcard Processor Node for that node type. If found, the Webflow invokes that destination.

  5. Searches for a superclass of the exception in the exception list of the Wildcard Processor Node for that node type. Again, if no destination is found, Webflow walks all the way up to the Exception exception.

  6. Searches for a configuration error page defined in the current namespace. If no configuration error page is defined in the current namespace, Webflow searches for one in the default namespace (as defined in the WEB-INF/web.xml file). If no configuration error page is defined, then Webflow has no choice but to 500 the user.

Input Processor and Pipeline Component Exception Handling

The Webflow mechanism knows nothing about Input Processors or Pipelines, as these are just Extension (Custom) Processors. This section contains information about how the Input Processor processor and the Pipeline Processor handle specific exceptions for Input Processors and Pipeline Components.

Input Processor Exceptions

When an Input Processor throws an exception, the Input Processor processor performs the following checks for the exception (in this order):

Pipeline Component Exceptions

When a Pipeline Component throws an exception, the Pipeline Executor performs the following checks for the exception (in this order):

JavaServer Page (JSP) Exception Handling

If the destination JavaServer Page (JSP) throws an exception while being rendered, there is nothing Webflow can do. This must be handled through normal JSP exception processing, with a JSP error page, or caught within the JSP itself.

Accessing Exceptions and Exception Messages

You can retrieve the original exception and/or the exception's message using the <webflow:getException> JSP tag. This tag can be inlined or the id attribute can be supplied to return the actual exception.

Note: For more information about the <webflow:getException> JSP tag, see <webflow:getException>.

Creating New Input Processor or Pipeline Component Exceptions

All Input Processors must throw the ProcessingException exception, one of its subclasses, or any other exception that Webflow is configured to handle.

Pipeline Components may throw a PipelineException exception, one of its subclasses, or any other exception that Webflow is configured to handle to signify that execution of the component has failed. Depending on whether or not the exception is configured as fatal or nonfatal, it is possible that no further Pipeline Components may be executed. If the Pipeline is transactional, the transaction will be rolled back.

Notes: See the related sections Configuring Pipeline Component Exception Fatality and Transactional Versus Nontransactional Pipelines. For more information about the ProcessingException or PipelineException exception, see the Javadoc.

Configuring Pipeline Component Exception Fatality

For those who used prior implementations of Webflow, you may recall that Pipeline Components could throw PipelineFatalException and PipelineNonFatalException exceptions. In this release, there is a general PipelineException exception that you can use or extend. Fatality of Pipeline exceptions depends upon how they are handled. Fatal Pipeline exceptions (also called abort exceptions) are those that are part of the abort exception list and therefore must be handled in the Webflow. Nonfatal Pipeline exceptions (called branch exceptions) are those that are handled inside the Pipeline by rerouting through another Pipeline Component.

In the Pipeline Editor, branch exceptions are shown as transitions between Pipeline Component Nodes, while abort exceptions are shown as transitions between a Pipeline Component Node and the Abort Exception Node.

If there are no exception transitions from any Pipeline Component Nodes to the Abort Exception Node, a default exception will be used when any Pipeline Component in that Pipeline throws an exception that is not handled as a branch exception. In this case, you can set the default exception behavior for the Abort Exception Node to either continue or abort the Pipeline using the Properties Editor.

A default abort exception of Continue is handled by ignoring the exception, continuing on to the next Pipeline Component, and passing a success event to the Pipeline Node in the Webflow namespace. A default abort exception of Abort is handled by throwing the unhandled exception to the Pipeline Node in the Webflow namespace. If the Pipeline is transactional, the transaction is rolled back to what it was before the Pipeline was started and then the exception is thrown.

Note: For more information about the Pipeline Editor, see Using the Webflow and Pipeline Editors.

 


Creating a New Input Processor

As you may recall from Input Processors and Pipelines, an Input Processor is one type of processor node that is typically used in a Webflow for form validation. BEA has developed a number of Input Processors that are packaged with the WebLogic Portal product suite, which you may want to reuse in your own applications. However, you may also want to create your own Input Processors for use in your applications' Webflows.

How to Create a New Input Processor

To create a new Input Processor, you must implement the com.bea.p13n.appflow.webflow.InputProcessor interface by providing the details of the process() method, which has the following method signature:

public Object process(HttpServletRequest req, Object requestContext) throws ProcessingException

Note: All classes located in PORTAL_HOME\applications\petflowApp\ petFlow\WEB-INF\src\examples\petflow\ip implement the InputProcessor interface, and can be viewed as examples.

Alternately, your new Input Processor can extend the com.bea.p13n.appflow.webflow.InputProcessorSupport class, as shown in Figure 4-2. As its name implies, this abstract class allows you to use static helper methods that provide additional support for an Input Processor. If your new Input Processor class must extend some other class, however, you will not be able to take advantage of the InputProcessorSupport class.

Figure 4-2 Relationship of the InputProcessorSupport Class


 

Note: For more information about the InputProcessor interface, the InputProcessorSupport class, or the ValidatedFormConstants interface, see the Javadoc.

When you are using the Webflow Editor to specify the properties for an Input Processor node you placed on the canvas, simply include the class name of your newly created Input Processor in the appropriate field. There are no additional activities you need to perform to make your Input Processor work with the existing Webflow mechanism.

Note: For more information about using the Webflow Editor, see Using the Webflow and Pipeline Editors.

Input Processor Naming Conventions

The name of an Input Processor should end with the suffix IP. For example, an Input Processor that is responsible for deleting a shipping address might be called DeleteShippingAddressIP. This naming convention should help you keep track of Input Processors more easily.

Input Processors and Statelessness

Like Pipeline Components, Input Processors are multi-threaded. To ensure that your Input Processors are thread safe, Input Processors should always be stateless, and it is recommended that you do not define any instance variables in an Input Processor.

Other Development Guidelines for Input Processors

Execution of business (application) logic should typically not be done within Input Processors. Specifically, Input Processors should not call Enterprise JavaBeans (EJBs) or attempt to access a database. All such logic should be implemented in Pipeline Components. Although it is possible to execute this logic within an Input Processor, such logic could not be transactional, and would defeat a primary purpose of the Webflow architecture. By separating business logic from the presentation logic, your Web site is inherently flexible in nature. Modifying or adding functionality can be as simple as creating and plugging in new Pipelines and/or Input Processors.

 


Webflow Validators and Input Processors

An Input Processor is essentially a Webflow component that works to validate data entered by a Web site visitor in an HTML form. Although you are not required to use Input Processors in your Webflows, use of Input Processors may increase developer productivity and will automatically preserve information the visitor originally entered while clearly identifying fields that require attention. Behind-the-scenes, Input Processors make use of a ValidatedValues interface to accomplish these tasks.

This section includes information about the following:

The ValidatedValues Interface

The ValidatedValues interface (shown in Figure 4-3) allows a Java/EJB developer who writes an Input Processor to report the status of processed form fields back to a HTML/JSP developer. The HTML/JSP developer receives the status of each form field in their Web pages via the <webflow:validatedForm> JSP tag. For more information about the <webflow:validatedForm> JSP tags, see Webflow JSP Tag Library Reference.

Figure 4-3 Validation Class Diagram


 

The ValidatedValues interface uses the imported javax.servlet.http.HTTPServletRequest. The public methods used to convey the status of the validation through the <webflow:getValidatedValue> and <webflow:setValidatedValue> JSP tags are shown in Table 4-1.

Table 4-1 ValidatedValues Public Methods

Method Signature

Description

public String getStatus (String name)

Retrieves the status for the specified field, which may be unspecified, invalid, or valid.

public void setStatus (String name, String value)

Sets the status for the specified field.

public Object getValue (String name)

Retrieves the current value for the specified field.

public String getValueAsString (String name)

Retrieves the current value of the field as a string. This method will return an empty string as opposed to null.

public void setValue (String name, String value)

Sets the value for the specified field.

public String getMessage (String name)

Retrieves the message for the field.

public void setMessage (String name, String value)

Sets the message for the field.

public int getInvalidFieldCount ()

Return the number of HTML form fields that did not validate.

public void setInvalidFieldCount(int count)

Set the number of HTML form fields that did not validate.

public void incInvalidFieldCount()

Increment the number of HTML form fields that did not validate.

public HttpServletRequest getHttpServletRequest()

Obtain a reference to the HttpServletRequest.


 

Note: For more information about the <webflow:getValidatedValue> and <webflow:setValidatedValue> JSP tags, see Webflow JSP Tag Library Reference. Please also be sure to visit the Javadoc for the most up-to-date information about the ValidatedValues class.

Validation Example

Listing 4-1 uses each of the validated form tags in an HTML form page that gathers some information about a Web site's visitors, which we will later validate using an Input Processor class and the ValidateValues interface.

Listing 4-1 The JSP Form Fields Requiring Validation

<%@ page import="com.bea.p13n.appflow.webflow.WebflowJSPHelper" %>
<%@ page import="java.util.Map" %>
<%@ taglib uri="webflow.tld" prefix="webflow" %>
<html>
<head>
<title>Webflow Demo</title>
</head>
<% String validStyle="background: white; color: black; font-family: Arial"; %>
<% String invalidStyle="background: white; color: red; font-style: italic"; %>
<%-- If there was an InvalidFormDataException thrown display the message --%>
<font size="5" color="green"><webflow:getException/></font>
<br>
<webflow:validatedForm event="button.go" applyStyle="message" 
messageAlign="right" validStyle="<%=validStyle%>"
invalidStyle="<%=invalidStyle%>" unspecifiedStyle="<%=validStyle%>" >
   <p>Username:
<webflow:text name="username" value="start" size="15" maxlength="30"
htmlAttributes="onMouseOver=\\"self.status='User ID';return true\\"" />
   <br>Password:
<webflow:password name="password" size="15" retainValue="true" maxlength="30"
htmlAttributes="onMouseOver=\\"self.status='Secret Password';return true\\""
/>
   <br>Number:
<webflow:text name="number" size="15" maxlength="30"/>
   <br>Phone:
<webflow:text name="phone" size="15" maxlength="15"/>
   <br>E-mail Phone:
<webflow:text name="email" size="15" maxlength="30"/>
   <br>Gender:
<webflow:radio name="gender" checked="true" value="M"/>Male
<webflow:radio name="gender" value="F" />Female
   <br>Animals(s) You Like:
<webflow:checkbox name="cat" value="cat" />Cat<br>
<webflow:checkbox name="dog" checked="true" value="dog" />Dog<br>
<webflow:checkbox name="bird" value="bird" />Bird
   <p>Comment:
<webflow:textarea name="comment" cols="20" rows="3" value="hello" />
   <br><br>Hobbies:
<webflow:select name="hobbies" size="3" multiple="true">
<webflow:option value="Running"/>Running
<webflow:option value="Skiing"/>Skiing
<webflow:option value="Motocross"/>MotoX
<webflow:option value="Rugby"/>Rugby
</webflow:select>
   <br>Pet You Own:
<webflow:select name="pets" size="1" >
<webflow:option value="dog" selected="true"/>Dog
<webflow:option value="cat" selected="false"/>Cat
<webflow:option value="bird" selected="false"/>Bird
</webflow:select>
   <br>
   <input type="submit"  name="Submit"/>
</webflow:validatedForm>
<br>
</html>

Note: For more information about the <webflow:validatedForm> JSP tags, see Webflow JSP Tag Library Reference.

The Input Processor shown in Listing 4-2 can be used to validate the form shown in Listing 4-1.

Listing 4-2 Example of an Input Processor process() Method

package com.bea.test.DemoIP;
import com.bea.p13n.appflow.common.PipelineSession;
import com.bea.p13n.appflow.exception.ProcessingException;
import com.bea.p13n.appflow.webflow.forms.ValidatedValues;
import com.bea.p13n.appflow.webflow.forms.ValidatedValuesFactory;
import com.bea.p13n.appflow.webflow.forms.ValidatedForm;
import com.bea.p13n.appflow.webflow.forms.ValidatedFormFactory;
import com.bea.p13n.appflow.webflow.forms.MissingFormFieldException;
import com.bea.p13n.appflow.webflow.forms.InvalidFormDataException;
import com.bea.p13n.appflow.webflow.forms.MinMaxExpression;
import examples.petflow.common.PetflowConstants;
import java.util.ArrayList;
import javax.servlet.http.HttpServletRequest;
public class DemoIP extends inputProcessorSupport
{
   public Object process(HttpServletRequest req, Object requestContext) throws 
ProcessingException, InvalidFormDataException
   {
   PipelineSession pSession = null;
String namespace = null;
pSession = getPipelineSession(req);
namespace = getCurrentNamespace(pSession);
ValidatedValues vValues = ValidatedValuesFactory.getValidatedValues(request);
ValidatedForm vForm = ValidatedFormFactory.getValidatedForm();
   // Validate the html form, let any missing fields bubble as a 
// MissingFormFieldException
   MinMaxExpression minMax = new MinMaxExpression();
   String username = vForm.validate(vValues, STRING_VALIDATOR, "username", 
minMax.set(4, 20), "User IDs must be greater then 4");
   String password = vForm.validate(vValues, STRING_VALIDATOR, "password", 
minMax.set(4, 20));
   String number   = vForm.validate(vValues, NUMBER_VALIDATOR, "number", 
minMax.set(1, 20));
   String phone = vForm.validate(vValues, PHONE_VALIDATOR, "phone", null);
   String email = vForm.validate(vValues, EMAIL_VALIDATOR, "email", null);
   String gender = vForm.validate(vValues, "gender");
   String cat = vForm.validate(vValues, "cat");
String dog = vForm.validate(vValues, "dog");
String bird = vForm.validate(vValues, "bird");
   String comment  = vForm.validate(vValues, STRING_VALIDATOR, "comment", 
minMax(0,255));
   Collection hobbies = vForm.validateMultiple(vValues, "hobbies", 2, "Must
select at least 2");
   String pets = vForm.validate(vValues, "pets");
   // Did all fields pass the validation test
   if (vValues.getInvalidFieldCount() > 0) 
   {
   // No, throw the InvalidFormFieldException and let Webflow
// redirect the user back to the origin JSP, preserving all our input
   throw new InvalidFormDataException("Please fix the fields in red and 
resubmit");
   }
   	// If you got here all form fields were entered correctly you probably want to 
// populate the Pipeline Session. Use the base class setRequestAttribute method
// to help you out
   return success;
   }
}

Special Validation Exceptions

There are three prewritten validation exceptions you may want to use with your Input Processors:

Creating a Custom Validator

In addition to the validators previously described, you may choose to create validators of your own.

To create a custom validator, you should create a class that implements the Validator interface (see Figure 4-3). Other guidelines for creating a custom validator include:

Example of a Custom Validator

Listing 4-3 shows an example of a custom validator that validates credit cards.

Listing 4-3 CreditCardValidator.java

package examples.petflow.ip.validator;
import com.bea.p13n.appflow.webflow.forms.Validator;
import com.bea.p13n.appflow.webflow.forms.ValidatedValues;
import java.util.StringTokenizer;
public class CreditCardValidator implements Validator
{
/**
* Validate a credit card number from an HTML Form.
* The card number is valid for 16 digits
* All separators "()- ." are first removed
* @param validatedValues object containing value, status,
messages
* @param key html form parameter name
* @return expression
*/
     public String validate(ValidatedValues validatedValues, String 
key, Object expression, String message)
    {
    // The value entered in the HTML form is supplied in the 
// ValidatedValues
       String value = validatedValues.getValueAsString(key);
value = value.trim();
    // Can optionally use the expression object to further refine 
// validation criteria
// if (expression != null && expression instanceof
// CreditCardExpression) ...
       StringBuffer buffer = new StringBuffer();
    // This stuff could come from the expression object
       StringTokenizer st = new StringTokenizer(value, "()- .");
char separator = ' ';
    // Strip any parentheses, spaces, dots and dashes
       while (st.hasMoreTokens()) {
buffer.append(st.nextToken());
}
    // Correct length?
        if (buffer.length() != 16) { 
validatedValues.setValue(key, value);
validatedValues.setStatus(key, STATUS_INVALID);

// If the user did not supply a message use the default.
// This can be retrieved from the internationalization message
// catalog.
          String msg = (message == null) ? "Credit cards must
have 16 digits" : message;
          validatedValues.setMessage(key, msg);
          return value;
        }
    // Make sure we have nothing but digits...
        try
{
Long.parseLong(buffer.toString());
}
catch (NumberFormatException e)
{
validatedValues.setValue(key, value);
validatedValues.setStatus(key, STATUS_INVALID);
    // If the user did not supply a message use the default.
// This can be retrieved from the internationalization message
// catalog.
            String msg = (message == null) ? "Credit card cannot 
contain letters, only digits" : message;
            validatedValues.setMessage(key, msg);
            return value;
        }
     // It is the validators responsibility to do any reformating 
// if necessary.
        StringBuffer creditCard = new StringBuffer(19);
        creditCard.append(buffer.substring(0,4));
creditCard.append(separator);
creditCard.append(buffer.substring(4,8));
creditCard.append(separator);
creditCard.append(buffer.substring(8,12));
creditCard.append(separator);
creditCard.append(buffer.substring(12,16));
     // Must set the value and the status in the validatedValues 
// object.
        value = creditCard.toString();
        validatedValues.setValue(key,  value);
validatedValues.setStatus(key, STATUS_VALID);
        return value;
    }
}

 


Creating a New Pipeline Component

As you may recall from Input Processors and Pipelines, a Pipeline is one type of processor node that is typically used in a Webflow to execute back-end business logic. Each Pipeline may contain a number Pipeline Components that perform specific tasks. BEA has developed a number of Pipeline Components that are packaged with the WebLogic Portal product suite that you may want to reuse in your own Pipelines. However, you may also want to create your own Pipeline Components to execute your organization's specific business processes.

How to Create a New Pipeline Component

New Pipeline Components must implement the com.bea.p13n.appflow.
pipeline.PipelineComponent
interface and must supply an implementation for the process() method. The process() method accepts a PipelineSession object as a parameter, and returns an updated PipelineSession object if the execution is successful, as shown in the following method signature:

public PipelineSession process(PipelineSession pipelineSession, Object requestContext)throws PipelineException,RemoteException;

Note: All of the classes located in the PORTAL_HOME\applications\petflowApp\ petFlow\WEB-INF\src\examples\petflow\ip directory implement the InputProcessor interface, and can be viewed as examples.

Alternately, your new Pipeline Component can extend the com.bea.p13n.appflow.pipeline.PipelineComponentSupport class, shown in Figure 4-4. As its name implies, this abstract class allows you to use methods that provide additional support for a Pipeline Component. If your new Pipeline Component class must extend some other class, however, you will not be able to take advantage of the PipelineComponentSupport class.

Figure 4-4 Relationship of the PipelineComponentSupport Class


 

Notes: For more information about the PipelineComponent interface or the PipelineComponentSupport class, see the Javadoc.

When you are using the Pipeline Editor to specify the properties for a Pipeline Component node you placed on the canvas, simply include the class name of your newly created Pipeline Component in the appropriate field. There are no additional activities you need to perform to make your Pipeline Component work with the existing Webflow mechanism.

Note: For more information about using the Pipeline Editor, see Using the Webflow and Pipeline Editors.

Pipeline Component Naming Conventions

The name of a Pipeline Component should end with the suffix PC. For example, a Pipeline Component that is responsible for saving a shopping cart might be called SaveCartPC. This naming convention should help you keep track of Pipeline Components more easily.

Implementation of Pipeline Components as Stateless Session EJBs or Java Objects

Pipeline Components can be implemented as either stateless session Enterprise JavaBeans (EJBs) or as Java objects. Table 4-2 describes the differences between the two implementations.

Table 4-2 Comparison of Pipeline Component Implementations

Stateless Session EJBs

Java Objects

Heavier in weight and more complex to implement due to EJB overhead.

Lightweight, low overhead.

Server-provided instance caching.

No instance caching, possibly degrading performance.

Server-provided load balancing.

No load balancing, always executes on the node in the cluster where the Pipeline started execution.

Can use ACL-based security according to EJB specification.

Must manage security.


 

An implementing class that is a stateless session EJB must meet the following requirements:

Stateful Versus Stateless Pipeline Components

Whether Pipeline Components are implemented as stateless session EJBs or as Java objects, Pipeline Components themselves should be stateless. The business logic implemented in Pipeline Components should only depend upon the PipelineSession object, the database, and other external resources. Should you define any instance variables, static variables, or static initializers within a Pipeline Component, the results may be unpredictable.

Transactional Versus Nontransactional Pipelines

If all Pipeline Components within the Pipeline will be invoked under one transaction, you should select the Make This Pipeline Transactional button in the Pipeline Editor. Transactional Pipelines provide support for rolling back the database transaction and for making changes to the Pipeline Session. If a transactional Pipeline fails, any database operations made by each of its Pipeline Components are rolled back.

If a Pipeline Component in a transactional Pipeline is implemented as a stateless session EJB, then its transactional property should be set to Required. If the Pipeline's is-transactional property is true and the participating Pipeline Components (EJBs) have their transaction flag set to never, the Pipeline will fail to execute. Similarly, if the Pipeline's is-transactional property is false and the Pipeline Components have the transaction flag set to mandatory, the Pipeline will also fail to execute.

If a Pipeline Component in a transactional Pipeline is implemented as a simple Java object, then for all database operations, the Pipeline Component must use the Transactional DataSource associated with the connection pool, as defined in the WebLogic Server Administration Console. A transactional Pipeline containing Pipeline Components implemented as simple Java objects commits the transaction upon success, and rolls back the transaction upon failure. Avoid demarcating transactions within the Pipeline Components themselves.

Including Pipeline Sessions in Transactions

If you include the Pipeline Session in a transaction, any failure in the transaction will cause the Pipeline Session's Pipeline Session-scoped properties to revert back to the state they were in prior to the transaction.

Note: Only Pipeline Session-scoped properties may be included as part of the transaction.

However, it is an expensive operation to serialize (even to memory) the Pipeline Session for each invocation. You will have much better performance if your Pipeline Session is not included in the transaction, so be sure you have a legitimate reason for including it.

Other Development Guidelines for Pipeline Components

All server-side coding guidelines apply for development of new Pipeline Components. Specifically:

 


Extending Webflow by Creating Extension Presentation and Processor Nodes

If creating new Input Processors and Pipeline Components to add to those BEA provides out-of-the-box does not meet your needs, you may also choose to extend the Webflow mechanism by creating classes that can be used as Extension (Custom) Presentation or Processor Nodes. Once you create the classes associated with these nodes, you will need to register the new nodes in the webflow-extensions.wfx file. This section includes information on how to perform these tasks.

How to Create an Extension Presentation Node

To create an Extension (Custom) Presentation Node, you must first create a class that implements the com.bea.p13n.appflow.webflow.PresentationNodeHandler interface. Be sure your class returns a URL that the WebflowServlet servlet can forward to. Then, you must register your extension node in the webflow-extensions.wfx file so it can be used in the Webflow and Pipeline Editors

Notes: For more information about the WebflowServlet servlet, see High-Level Architecture. For instructions on how to register your extension node in the webflow-extensions.wfx file, see Making Your Extension Presentation and Processor Nodes Available in the Webflow and Pipeline Editors.

The portal application makes use of an Extension (Custom) Presentation Node named portal, which you can view as an example. The portal application uses this extension node to indicate to the portal Webflow that the contents of the portlet are to remain unchanged (that is, it indicates that the last URL should be displayed). The portal node's implementation class is LastContentUrlNodeHandler.java.

How to Create an Extension Processor Node

Figure 4-5 illustrates the basic architecture of the Webflow mechanism. As the figure shows, you may want to create an Extension (Custom) Processor that functions at the same level as an Input Processor processor or Pipeline Processor. In fact, the Input Processor processor and Pipeline Processor can be thought of as examples of Extension Processors.

Figure 4-5 Webflow High-Level Architecture


 

Extension (Custom) Processors are processors that your organization (as opposed to BEA) develops for use in your applications' Webflows. Extension Processors may be used to perform activities not currently supported by the Webflow. However, the flow in and out of an Extension Processor is still governed by the Webflow mechanism. Extension Processors are represented as nodes in the Webflow Editor, much like the Input Processor and Pipeline Nodes are, but with a slightly different representation for easy identification.

Note: For more information about using the Webflow Editor, see Using the Webflow and Pipeline Editors.

For example, you may want to create an Extension (Custom) Processor that works with the BEA Rules Engine to support different Webflows based on some condition, such as membership in a customer segment. Another, more simple example might be a layout manager processor that automatically includes a header and footer in your JavaServer Pages (JSPs) when given the page's body content. In fact, we have already created such a processor.

To create an Extension (Custom) Processor Node, you must first create a class that implements the com.bea.p13n.appflow.webflow.Processor interface to define the Extension Processor. Then, you must register your processor in the webflow-extensions.wfx file so it can be used in the Webflow and Pipeline Editors.

Note: For instructions on how to register your extension node in the webflow-extensions.wfx file, see Making Your Extension Presentation and Processor Nodes Available in the Webflow and Pipeline Editors.

Making Your Extension Presentation and Processor Nodes Available in the Webflow and Pipeline Editors

After you have created an Extension (Custom) Presentation or Processor Node, you must make that node available to other developers on your team by registering the node in the webflow-extensions.wfx file.

Notes: The webflow-extensions.wfx file resides within your Web application's home directory and is therefore scoped to a Web application.

Registering an Extension (Custom) Processor Node will cause its corresponding tool on the Webflow Editor palette to become enabled once you restart the E-Business Control Center (EBCC).

How To Register an Extension Presentation Node

To register an Extension Presentation Node in the webflow-extensions.wfx file, follow these steps:

  1. Add an <end-node> element to the <end-node-registration> list.

  2. Assign your presentation node a name with the Name attribute, and specify the class of the underlying node implementation with the Node-handler attribute.

  3. Define the input parameters that the class expects upon invocation, using <node-processor-input> elements. Give each parameter a Name, and if the parameter is optional, assign the Required attribute a value of false.

    Note: This information will be used in the Webflow and Pipeline Editors' Property Editors.

  4. Save the webflow-extensions.wfx file, and restart the E-Business Control Center.

Listing 4-4 provides an example of registering an Extension Presentation Node in the webflow-extensions.wfx file.

How To Register an Extension Processor Node

To register an Extension Processor Node in the webflow-extensions.wfx file, follow these steps:

  1. Add a <process> element to the <process-registration> list.

  2. Assign your processor a name with the Name attribute, and specify the class of the underlying processor implementation with the Executor attribute.

  3. Define the input parameters that the class expects upon invocation, using <node-processor-input> elements. Give each parameter a Name, and if the parameter is optional, assign the Required attribute a value of false.

    Note: This information will be used in the Webflow and Pipeline Editors' Property Editors.

  4. Save the webflow-extensions.wfx file, and restart the E-Business Control Center.

Listing 4-4 provides an example of registering an Extension Processor Node in the webflow-extensions.wfx file.

Listing 4-4 Sample webflow-extensions.wfx File

<?xml version="1.0" encoding="UTF-8" ?> 
<webflow-extensions 
xmlns="http://www.bea.com/servers/p13n/xsd/webflow-extension/1.0"
xmlns:xsi="http://www.w3.org/2000/10/XMLSchema-instance"
xsi:schemaLocation="http://www.bea.com/servers/p13n/xsd/webflow-extension/1.0
webflow-extensions.xsd">
   <process-registration> 
      <process name="inputprocessor" 
executor="com.bea.p13n.appflow.webflow.internal.IPProcessor">
<node-processor-input name="class-name" required="true" />
</process>
      <process name="pipeline" 
executor="com.bea.p13n.appflow.webflow.internal.PipelineProcessor">
<node-processor-input name="pipeline-namespace" required="false" />
<node-processor-input name="pipeline-name" required="true" />
</process>
      <process name="layoutmanager" 
executor="examples.petflow.layout.LayoutProcessor">
<node-processor-input name="header" required="true" />
<node-processor-input name="content" required="true" />
<node-processor-input name="footer" required="true" />
</process>
   </process-registration> 
   <end-node-registration> 
      <end-node name="jsp" 
node-handler="com.bea.p13n.appflow.webflow.internal.GenericNodeHandler">
<node-processor-input name="page-relative-path" required="false" />
<node-processor-input name="page-name" required="true" />
</end-node>
      <end-node name="html" 
node-handler="com.bea.p13n.appflow.webflow.internal.GenericNodeHandler">
<node-processor-input name="page-relative-path" required="false" />
<node-processor-input name="page-name" required="true" />
</end-node>
      <end-node name="htm"
node-handler="com.bea.p13n.appflow.webflow.internal.GenericNodeHandler">
<node-processor-input name="page-relative-path" required="false" />
<node-processor-input name="page-name" required="true" />
</end-node>
      <end-node name="servlet" 
node-handler="com.bea.p13n.appflow.webflow.internal.ServletNodeHandler">
<node-processor-input name="request-uri-path" required="true" />
</end-node>
      <end-node name="portal"
node-handler="com.bea.portal.appflow.internal.LastContentUrlNodeHandler">
<node-processor-input name="page-name" required="true"/>
</end-node>
   </end-node-registration> 
</webflow-extensions>

 


Webflow Internationalization

The WebLogic Portal product suite uses message catalogs that are in XML format for purposes of internationalization. For more information about the message catalog and internationalization, see Overview of Internationalization for WebLogic Server in the BEA WebLogic Server Internationalization Guide.

 

back to top previous page next page