Writing a Custom Filter using the Oracle Enterprise Gateway SDK

Contents

Tutorial Overview

Oracle Enterprise Gateway exposes several powerful APIs as part of its Software Development Kit (SDK) to enable users to build their own bespoke message filters. Users can leverage Oracle Enterprise Gateway's pluggable and extensible architecture to enhance the message processing capabilities of the Oracle Enterprise Gateway core processing engine.

This tutorial walks you through a step-by-step example of how to build a custom-built message filter with the SDK, and integrate it into a Oracle Enterprise Gateway policy. This tutorial shows how to build the two main aspects of an Addition filter: the server runtime component, and the Policy Studio configuration component. It then integrates these components into a Oracle Enterprise Gateway policy, and shows how the filter adds the values of two parameters of a SOAP message together, and returns the result to the client. By the end of this tutorial, you should be able to write and test your own message filters by following a similar procedure.

Before going any further, however, it is important to explain exactly what are Oracle Enterprise Gateway filters and to see exactly how they can be wired together to create message processing policies.

Policies, Filters, and Message Attributes

A policy consists of a network of message filters where each filter is a modular executable unit that performs a specific type of processing on a message. The policy arranges these filters into sequences called paths. The filters then act as decision-making points along these paths, determining which filters are run on the message, and in what order.

The following four-node policy contains a single path with four message filters. The filter marked as Start (AuthN: WS-Security Username Token) is executed first. If this filter runs successfully, the next filter in the path (getQuotes Operation Name) is run, and so on until the last filter (Echo Web Service) in the path is executed.

Simple Circuit

Simple Circuit

When an HTTP request is received, it is converted into a set of message attributes. Each message attribute represents a specific characteristic of the HTTP request, such as the HTTP headers, HTTP body, and MIME parts, amongst others.

Every Filter declares the message attributes that it requires, generates, and consumes from the attributes blackboard. The blackboard contains all the available message attributes. When a filter generates message attributes it puts them up on the blackboard so that when another Filter requires them it can pull them off the blackboard. If a filter consumes a message attribute, it is wiped from the blackboard so that no other filter in the policy can use it.

The following table summarizes the attributes required and generated by the Operation Name resolver, which filters incoming requests based on their SOAP operation and namespace:

Filter Name: Operation Name
Description: Filters incoming SOAP requests based on their SOAP operation and namespace.
Required Attributes: content.body
http.request.uri
Generated Attributes: soap.request.method

For more information on policy, policy building, filters, please refer to your Enterprise Gateway documentation. The following list summarizes the important concepts introduced in this section:

  • Policy:
    A network of interconnected message filters.
  • Message Filters:
    An executable unit that performs a specific type of processing on message attributes.
  • Message Attributes:
    Message attributes represent specific characteristics of a message.

Oracle Enterprise Gateway SDK Overview

The Oracle Enterprise Gateway Software Development Kit (SDK) comprises three Java packages that provide programmatic access to Oracle Enterprise Gateway policies, message objects, and the Entity Store. The following table describes these packages:

Package Description
com.vordel.circuit This package is responsible for implementing the core Oracle Enterprise Gateway policy. It includes the base classes for all message filters and their associated classes.
com.vordel.mime Includes classes that encapsulate the message as it passes through the Oracle Enterprise Gateway policy. It also provides programmatic access to HTTP headers, HTTP body, request query string (if present), and MIME parts.
com.vordel.es These classes provide access to the underlying Entity Store where all configuration data is stored.


Tutorial Prerequisites

You should read Getting Started to make sure you understand the concepts of policies and filters before continuing.

The Oracle Enterprise Gateway SDK requires a JDK 1.6, and is supported for the Windows, Linux, and Solaris packages.

Oracle Enterprise Gateway SDK Sample Overview

The Oracle Enterprise Gateway SDK ships with a working example of a message filter, called the SimpleFilter, that demonstrates how to use the SDK to build a filter. The filter extracts two integer parameters from a SOAP message, adds the integers, and returns the result of the addition in a SOAP response to the client.

This tutorial documents the steps required to build, integrate, configure, and test the supplied SimpleFilter and SimpleProcessor classes. The steps are as follows:

Step Description
Step 1: Create TypeDocs Every filter has an associated XML-based TypeDoc that contains the entity's type definition. It defines the configuration field names for that filter and their corresponding data types.
Step 2: Create Filter Class Every message filter has an associated Filter class that encapsulates the configuration data for a particular instance of the filter. It also returns the corresponding Processor and Policy Studio classes.
Step 3: Create Processor Class The Processor class is the server runtime component that is responsible for processing the message. Every message filter has an associated Processor and Filter class.
Step 4: Create Policy Studio Classes All Filters are configured using the Policy Studio. Every Filter has a configuration wizard that enables you to set each of the fields defined in the entity that corresponds to that Filter. You can then add the filter to a policy to process messages.
Step 5: Build Classes When the classes have been written, they must be built and added to the server and client classpaths.
Step 6: Load TypeDocs The TypeDoc that is created for the filter in Step 1 must be registered with the Entity Store.
Step 7: Construct a Policy This step constructs a policy that echoes messages back to the client, and then adds the newly created filter to it.
Step 8: Configure the SimpleFilter This step uses the GUI component of the newly added filter to configure its configuration fields. It then tests the functionality of the filter (and its configuration) using the Oracle Service Explorer testing tool.


Step 1: Create the Typedocs

All configuration data is stored as entities in the Oracle Enterprise Gateway Entity Store. The Entity Store is an XML-based store that holds all configuration data required to run the Oracle core processing engine. Each configurable item has an entity type definition. The entity type definition is defined in an XML file known as the TypeDoc.

Entity types are analogous to class definitions in an object-oriented programming language. In the same way that instances of a class can be created in the form of objects, an instance of an entity type can also be created. Therefore it is useful to think of the entity type defined in a TypeDoc as a header file, and the entity itself as a class instance. All entities and their entity type definitions are stored in the Entity Store.

Every filter requires specific configuration data to perform its processing on the message. For example, the SimpleFilter, which extracts the values of two elements from a SOAP message, and adds them together, must be primed with the names and namespaces of those two elements.

Because a filter is a configurable item, it requires a new XML typedoc to be written containing an entity type definition for it. The entity type for a filter contains a set of configuration parameters and their associated data types and default values.

When an instance of the filter is added to a policy using the Policy Studio, a corresponding entity instance is created and stored in the Entity Store. Whenever the filter instance is invoked, its configuration data is read from the entity instance in the Entity Store.

TypeDoc Syntax
The following example XML shows how the TypeDoc lists the various fields that form the configuration data for the Filter.

<entityStoreData> 
  <entityType name="SimpleFilter" extends="Filter">
    <!-- Name of filter class that encapsulates the config data -->
    <constant name="class" type="string" 
                 value="com.vordel.example.filter.SimpleFilter"/>
    <!-- List of config fields, their types, and their default values -->
    <field ... /> 
    <field ... /> 
    <field ... /> 
  </entityType> 
<entityStoreData> 

All TypeDocs must obey the following simple rules:

  • Extend the Filter type
  • Define a constant Filter class
  • List the configuration fields for the entity

SimpleFilter Elements and Attributes
The following table describes the important elements and attributes from the SimpleFilter TypeDoc listed above:

Element Attribute Description
<entityStoreData> The topmost wrapper element for the entire type definition.
<entityType> Contains the type definition, including all its fields and their types.
<entityType> name The unique name for this type.
<entityType> extends Entity definitions are hierarchical and can inherit from other higher level types. All filters must extend the Filter type.
<constant> A <constant> element is used to represent a read-only immutable property of the type.
<constant> name This attribute contains the name of the read-only property. In the example above, the named property is class, indicating that the value of this constant is the Java class that encapsulates the defined type. The name of this class must be specified as a <constant>.
<constant> type Specifies the type of the value attribute. In this case, the value is the name of a Java class, which is just a string.
<constant> value Contains the value of the named property, which is the name of the Java class that encapsulates this type (com.vordel.example.filter.SimpleFilter).
<field> Contains the definition of a single configuration field for this filter.
<field> name The name of the configuration field. You can see later in this tutorial how this name is used to get and set this property.
<field> type Specifies the data type of the named configuration field. For example, supported types include string, boolean, encrypted, and integer.
<field> cardinality Stipulates how many times this field can appear in an instance of the entity. For example, a cardinality of 1 means that this field can only occur once within an entity.
<field> default Specifies a default value for the configuration field, if appropriate.

SimpleFilter TypeDoc
The TypeDoc for the SimpleFilter is as follows:

<entityStoreData> 
  <entityType name="SimpleFilter" extends="Filter">
  
    <!-- Name of Filter class that encapsulates this config entity -->
    <constant name="class" type="string" 
                 value="com.vordel.example.filter.SimpleFilter"/>
    
    <!-- List of config params, their types, and their default values -->
    <field name="param1" type="string" cardinality="1" default="a"/>  
    <field name="param1Namespace" type="string" 
              cardinality="1" default="http://startvbdotnet.com/web/"/>  
    <field name="param2" type="string" cardinality="1" default="b"/>  
    <field name="param2Namespace" type="string" 
              cardinality="1" default="http://startvbdotnet.com/web/"/>  
  </entityType> 
</entityStoreData>    

All type and related information for the Filter is contained in the top-level <entityStoreData> element. The Filter type declaration together with its field definitions and types are child elements of the <entityType> element. Each field name is specified in the name attribute of the <field> element, while the type and default value for the field are specified in the type and default attributes, respectively.

You can also provide internationalized log messages by specifying an <entity> block of type InternationalizationFilter within the <entityStoreData> elements.

Now that you understand how the configuration data for the filter is defined, you can create the filter class.


Step 2: Create the Filter Class

A filter class encapsulates the type information defined in an entity's type definition. There are class members that correspond to each of the fields in the type definition. At runtime, when the filter is invoked, the filter class is instantiated with the configuration data for the appropriate entity instance. The filter class is responsible for the following tasks:

  • Storing member variables corresponding to fields in the type definition
  • Specifying the message attributes it requires, consumes, and generates
  • Returning the corresponding server runtime class (the Processor)
  • Returning the corresponding Policy Studio class

SimpleFilter Class
The following code shows the members and methods of the SimpleFilter.java example:

package com.vordel.example.filter;

import com.vordel.circuit.DefaultFilter;
import com.vordel.circuit.FilterConfigureContext;
import com.vordel.circuit.MessageProperties;
import com.vordel.es.EntityStoreException;

 /**
 SimpleFilter contains the local name of the two 
 parameters (a and b) and contains the namespace that 
 these elements belong to (http://startvbdotnet.com/web/)
  **/

public class SimpleFilter extends DefaultFilter {  
   
    // element name of the first parameter
    String param1;
    // namespace of the first element
    String param1Namespace;
    // element name of the second parameter
    String param2;
    // namespace of the second parameter
    String param2Namespace;

    /**
     * Set the message attributes used by this filter
     */
    protected final void setDefaultProperties() {
        requiredProperties.add(MessageProperties.CONTENT_BODY);
    }
    
    /**
     * This method is called to set the config fields for the filter
     * @param ctx The configuration context for this filter
     * @param entity The entity object
     */
    public void configure(FilterConfigureContext ctx, 
                            com.vordel.es.Entity entity)
                            throws EntityStoreException {
        
        super.configure(ctx, entity);
        
        // read the settings for the processor
        param1  = entity.getStringValue("param1");
        param1Namespace  = entity.getStringValue("param1Namespace");
        param2  = entity.getStringValue("param2");
        param2Namespace  = entity.getStringValue("param2Namespace");
    }
 
    /**
     * Returns the server runtime Processor class associated 
     * with this Filter class.
     */
    public Class getMessageProcessorClass() {
        return SimpleProcessor.class;
    }
    
    /**
     * Returns the GUI component for this Filter 
     */
    public Class getConfigPanelClass() throws ClassNotFoundException {
        // Avoid any compile or runtime dependencies on SWT and other UI 
        // libraries by lazily loading the class when required.
        return 
            Class.forName("com.vordel.example.filter.simple.SimpleFilterUI");
    }
}    

SimpleFilter TypeDoc
At this point, it is worth revisiting the entity definition for the SimpleFilter entity to see how the class members correlate to the defined fields.

<entityType name="SimpleFilter" extends="Filter">
  
  <!-- Name of Filter class that encapsulates this config entity -->
  <constant name="class" type="string" 
               value="com.vordel.example.filter.SimpleFilter"/>
   
  <!-- List of config params, their types, and their default values -->
  <field name="param1" type="string" cardinality="1" default="a"/>  
  <field name="param1Namespace" type="string" 
            cardinality="1" default="http://startvbdotnet.com/web/"/>  
  <field name="param2" type="string" cardinality="1" default="b"/>  
  <field name="param2Namespace" type="string" 
            cardinality="1" default="http://startvbdotnet.com/web/"/>  
</entityType> 

SimpleFilter Methods
The Filter class members (param1, param1Namespace, param2, and param2Namespace) directly correspond to the field definitions in the type definition. These members are populated in the configure method of the Filter class, which is called by the framework when the server is started up initially, and whenever the server is refreshed. The Entity class provides getter and setter methods for the different data types (for example, string, boolean, integer, and so on). For more details, see the Entity Javadoc.

There are two more important methods implemented in this class: setDefaultProperties and getMessageProcessorClass. The setDefaultProperties method enables the Filter to define the message attributes that it requires, generates, and consumes from the attributes blackboard. The blackboard contains all the available message attributes. When a filter generates message attributes, it puts them up on the blackboard so that when another Filter requires them, it can pull them off the blackboard. If a filter consumes a message attribute, it is wiped from the blackboard so that no other filter in the policy can use it.

The attributes are stored in String arrays (reqProps, genProps, conProps), which are inherited from the VariablePropertiesFilter class. In the case of the SimpleFilter class, the content.body attribute is required because the SOAP parameters must be extracted from the body of the HTTP request.

The next important method here is the getMessageProcessorClass method, which returns the server runtime component (the Processor class) that is associated with this Filter class. Each Filter class has a corresponding Processor class, which is responsible for using the configuration data stored in the Filter class to process the message. The next step looks at the SimpleProcessor class to see how it acts on the data stored in the SimpleFilter class.

Finally, the corresponding Policy Studio configuration class is returned by the getConfigPanelClass method, which in this case is the com.vordel.example.filter.simple.SimpleFilterUI class. This class is described in detail in Step 4 of this tutorial.

Step 3: Create Processor Class

The Processor class is responsible for performing the processing on the message. It uses the configuration data stored in the Filter class to determine how to process the message. It is important to note that this is the server runtime component of the filter that is returned by the getMessageProcessorClass of the Filter class described in the previous section.

Example Skeleton Code
The following skeleton code shows how the Processor attaches to the Filter class and uses its data to process the message. The following code is for illustration purposes only, and some of the SimpleProcessor code has been omitted.

package com.vordel.example.filter;

import java.io.ByteArrayInputStream;
import java.io.IOException;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;

import com.vordel.circuit.Circuit;
import com.vordel.circuit.CircuitAbortException;
import com.vordel.circuit.Filter;
import com.vordel.circuit.Message;
import com.vordel.circuit.MessageProcessor;
import com.vordel.circuit.MessageProperties;
import com.vordel.es.EntityStore;
import com.vordel.mime.Body;
import com.vordel.mime.ContentType;
import com.vordel.mime.HeaderSet;
import com.vordel.mime.XMLBody;
import com.vordel.trace.Trace;

/**
 * This Processor acts as a simple Addition Web Service.
 * It extracts two parameters from a SOAP message and adds them together.
 * The result is then returned to the client.
 * The incoming message is expected in the following format:

<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
  <soap:Body>
    <Add xmlns="http://startvbdotnet.com/web/">
      <a>1</a>
      <b>1</b>
    </Add>
  </soap:Body>
</soap:Envelope>

 The SimpleFilter contains the local name of the two parameters (a 
 and b), and contains the namespace that these elements belong to 
 (http://startvbdotnet.com/web/).
 */
public class SimpleProcessor extends MessageProcessor {

     /**
     * This method attaches the Filter to the Processor object.
     * This is called at startup and on every refresh.
     * This should contain server-side config/initialization.  
     * For example, if this filter is required to establish 
     * connections to any 3rd party products/servers, the 
     * connection setup should be done here.
     * @param ctx Configuration context for the filter.
     * @param entity The Entity object
     */
    public void filterAttached(FilterConfigureContext ctx, 
                                com.vordel.es.Entity entity) 
                                throws EntityStoreException {
        // nothing to do here for initialisation
        super.filterAttached(ctx, entity);
    }

    /**
     * The invoke method performs the filter processing.
     * @param c The circuit
     * @param message The message
     * @return true or false.
     */
    public boolean invoke(Circuit c, Message message) 
      throws CircuitAbortException {

        try {
            // Get the incoming request message as a DOM
            Document doc = getDOM(message);

            // Default result
            String result = "UNKNOWN";     

            // Cast the filter member variable to a SimpleFilter so that 
            // you may access the values stored in the SimpleFilter's 
            // fields (for example, param1, param1Namespace, and so on).
            SimpleFilter f = (SimpleFilter)filter;

            // Look into the DOM to get the two parameters.
            // Get the 1st parameter
            NodeList param1 =
                doc.getElementsByTagNameNS(f.param1Namespace, f.param1);
            if (param1 == null || param1.getLength() <= 0)
                throw new CircuitAbortException(
                    "Could not find " + f.param1 + "in message");
            // Get the value passed in the 1st parameter
            String a = getElementContent((Element)param1.item(0));
            
            // Get the 2nd parameter
            NodeList param2 = 
                doc.getElementsByTagNameNS(f.param2Namespace, f.param2);
            if (param2 == null || param2.getLength() <= 0)
                throw new CircuitAbortException(
                    "Could not find " + f.param2 + "in message");
            
            // Get the value of the 2nd parameter
            String b = getElementContent((Element)param2.item(0));

            // Calculate the result by adding the two parameter values
            result = 
                Integer.toString(Integer.parseInt(a) + Integer.parseInt(b));

            // Set the response by setting the content body 
            // to be the response
            HeaderSet responseHeaders = new HeaderSet();
            responseHeaders.putString("Content-Type", "text/xml");
            StringBuffer response = new StringBuffer(RESPONSE_START);
            response.append(result);
            response.append(RESPONSE_END);
            Body convertedBody =
                Body.create(responseHeaders, new ContentType("text/xml"),
                    new ByteArrayInputStream(
                        response.toString().getBytes()));
            message.setProperty(
                MessageProperties.CONTENT_BODY, convertedBody);

            return true;
        }
        catch (IOException exp) {
            Trace.error("IOException in SimpleProcessor: " + exp.getMessage());
            return false;
        }
    }
}

Processor Methods
There are two important methods that must be implemented by every Processor: the filterAttached method and the invoke method. The filterAttached method associates an appropriate Filter class with the Processor. The Processor can then access the configuration data stored in the Filter class. In this case, the SimpleProcessor attaches to the SimpleFilter class. The filterAttached method should contain any server-side initialization or configuration that is to be performed by the Filter, such as connecting to third-party products or servers.

The invoke method is responsible for using the data stored in the attached Filter class to perform the message processing. This method is called by the server as it executes the series of filters in any given policy. In the case of the SimpleFilter, the invoke method extracts the values of the <a> and <b> elements from the SOAP message, and adds the two values together. The result is then returned to the client in a templated SOAP response.

It is important to note that the invoke method can have the following possible results:

Result Description
True If the filter processed the message successfully (for example, successful authentication, schema validation passed, and so on), the invoke method should return a true result, meaning that the next filter on the success path for the filter is invoked.
False If the filter's processing fails (for example, the user was not authenticated, message failed integrity check, and so on), the invoke method should return false, meaning that the next filter on the failure path for the filter is invoked.
CircuitAbortException If for some reason the filter cannot process the message at all (for example, if it can not connect to an Identity Management server to authenticate a user), it should throw a CircuitAbortException. If a CircuitAbortException is thrown in a policy, the designated Fault Processor (if any) is invoked instead of any successive filters on either the success or failure paths.

Now that you have a class to encapsulate the configuration data and another class to act on that data, it is now time to create some GUI classes where the user can configure the fields stored in the Filter class.

Step 4: Create Policy Studio Classes

The next step involves writing two GUI classes so that the fields defined in the SimpleFilter type definition can be configured. When the GUI classes and resources have been built, the visual components can be used in the Policy Studio to configure the Filter and add it to a policy.

SimpleFilter GUI Classes and Resources
The following table describes the GUI classes and resources that relate to the SimpleFilter:

Class or Resource Description
SimpleFilterUI.java This class is used to list the pages that are involved in a Filter's configuration screen. Each Filter has at least two pages: the main configuration page, and a page where log messages related to the filter can be customized. This class is returned by the getConfigPanelClass method of the SimpleFilter class.
SimpleFilterPage.java This class defines the layout of the visual fields on the Filter's main configuration screen. For example, there are four text fields on the configuration screen for the SimpleFilter corresponding to the four fields defined in the entity's type definition.
resources.properties This file contains all text that is displayed in the GUI configuration screen (for example, dialog titles, field names, and error messages). This means that the text can be customized or internationalized easily without the need for code change.
simple.gif This image file is used as the icon to identify the Filter in the Management Console, and is displayed in the Filter Palette.

This step first looks at the SimpleFilterUI class, which is returned by the getConfigPanelClass method of the SimpleFilter class. It is responsible for the following:

  • Listing the configuration pages that make up the interface for the filter
  • Naming the category of filters to which this filter belongs
  • Specifying the name of the images to use as the icons/images for this filter

SimpleFilterUI Class
The code for the SimpleFilterUI is as follows:

package com.vordel.example.filter.simple;

import java.util.Vector;

import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.swt.graphics.Image;

import com.vordel.client.manager.Images;
import com.vordel.client.manager.filter.DefaultGUIFilter;
import com.vordel.client.manager.wizard.VordelPage;

/**
 * Filter configuration GUI for 'Simple' example filter.
 * This class shows how to code simple text fields for configuring a
 * custom filter.
 */
public class SimpleFilterUI 
    extends DefaultGUIFilter 
{
    /**
     * Add the pages you want to show in the configuration wizard for the filter.
     */
    public Vector<VordelPage> getPropertyPages() {
        Vector<VordelPage> pages = new Vector<VordelPage>();
        
        // Add the panel for configuring the specific fields
        pages.add(new SimpleFilterPage());
        
        // Add the page which allows the user to set the log strings for the 
        // audit trail, for the pass/fail/error cases
        pages.add(createLogPage());
        
        return pages;
    }
    
    /**
     * Set the categories in which you want to display this Filter. The 
     * categories define the sections of the palette in which the Filter 
     * appears. The values returned should be the localized name of the 
     * palette section, so ensure that the property is defined in the 
     * resources.properties in this class' package. You will add this 
     * file to the "Example Filters" category.
     */
    public String[] getCategories() {
        return new String[]{_("FILTER_GROUP_EXAMPLE")};
    }
    
    /*
     *  Register our custom images with the image registry
     */
    private static final String IMAGE_KEY = "simpleFilter";
    static {
        Images.getImageRegistry().put(IMAGE_KEY, 
                Images.createDescriptor(SimpleFilterUI.class, "simple.gif"));
    }
    
    /**
     *  The icon image needs to be added in images.properties in com.vordel.client.manager
     *  the id used there is used as a reference here.
     *  Use this method to get image id for the small icon image in Images.get(id), etc.
     */
    public String getSmallIconId() {
        return IMAGE_KEY;
    }
    
    /**
     * Implement this method if you want to display a non-default image
     * for your filter in the circuit editor canvas and navigation tree.
     */
    public Image getSmallImage() {
        return Images.get(IMAGE_KEY);
    }
    
    /**
     * Implement this method to display a non-default icon for your filter in 
     * the palette.
     */
    public ImageDescriptor getSmallIcon() {
        return Images.getImageDescriptor(IMAGE_KEY);
    }
}    

SimpleFilterUI Methods
The following table describes the important methods:

Method Description
public Vector getPropertyPages() Initializes a Vector of the Pages that makeup the total configuration screens for this Filter. Successive Pages are accessible by clicking the Next button on the Policy Studio configuration screen.
public String[] getCategories() This method returns the names of the Filter categories that this Filter belongs to. The Filter is displayed under these categories in the Filter Palette in the Policy Studio. The SimpleFilter is added to the Example Filters category.
public Image getSmallImage() The default image for the Filter, which is registered in the static block in the code above, can be overridden by returning a different image here.
public ImageDescriptor getSmallIcon() The default icon for the Filter can be overridden by returning a different icon here.

A Page only represents a single configuration screen in the Policy Studio. You can chain together several Pages to form a series of configuration screens that together make up the overall configuration for a given Filter. By default, all Filters consist of two pages: one for the configuration fields for the Filter, and the other to allow per-Filter logging. However, there is no reason why more Pages can not be chained together. Successive Pages should be added to the configuration in the getPropertyPages method.

From looking at the getPropertyPages method of the SimpleFilterUI, it is clear that the SimpleFilterPage class forms one of the configuration screens (or pages) for the SimpleFilter filter. The SimpleFilterPage class is responsible for the layout of all the input fields that make up the configuration screen for the SimpleFilter.

SimpleFilterPage Class
The code for the SimpleFilterPage class is shown below:

package com.vordel.example.filter.simple;

import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;

import com.vordel.client.manager.wizard.VordelPage;

public class SimpleFilterPage extends VordelPage 
{    
    /** 
     * Create the configuration page. Set the title and description 
     * here. The title and description are maintained in the 
     * resources.properties file for customization and 
     * internationalization purposes.
     */
    public SimpleFilterPage() {
        // Call the super constructor with a unique name for this 
        // page to bind it with its corresponding wizard.
        super("simplePage");
        setTitle(_("SIMPLE_PAGE"));
        setDescription(_("SIMPLE_PAGE_DESCRIPTION"));
        setPageComplete(false);
    }
    
    /**
     * Get the unique identifier for the help page for this filter. 
     * The id-to-page mapping is maintained in the 
     * '/docs/res/help.jhm' file. The URL for the page to describe 
     * the filter should be relative to the '/docs' directory. 
     */
    public String getHelpID() {
        return "simple.help";
    }

    /**
     * Any post-processing of the configuration values can happen 
     * here, before they are persisted to the Entity Store. If the 
     * configuration is not complete and valid, notify the user here 
     * with a dialog box and return false here, otherwise return true.
     * 
     * @see com.vordel.client.manager.util.MsgBox
     */
    public boolean performFinish() {
        // Simple mutually independent values here, no checking required, 
        // so return true
        return true;
    }

    /**
     * Create the main control for the Filter configuration dialog. 
     * This will house the text fields for setting the particular 
     * Field Values in the Entity.
     */
    public void createControl(Composite parent) {
        // Create a Panel with two columns        
        GridLayout layout = new GridLayout();
        layout.numColumns = 2;    
        Composite container = new Composite(parent, SWT.NULL);
        container.setLayout(layout);
        
        // Add controls to populate the appropriate Entity Fields
        // You use the localization keys for the field names and 
        // descriptions which will map to entries in the 
        // resources.properties file.        
        createLabel(container, "SF_NAME");
        createTextAttribute(container, "name", "SF_NAME_DESC");

        createLabel(container, "SF_PARAM1");
        createTextAttribute(container, "param1", "SF_PARAM1_DESC");
        
        createLabel(container, "SF_PARAM1NS");
        createTextAttribute(container, "param1Namespace", "SF_PARAM1NS_DESC");

        createLabel(container, "SF_PARAM2");
        createTextAttribute(container, "param2", "SF_PARAM2_DESC");
        
        createLabel(container, "SF_PARAM2NS");
        createTextAttribute(container, "param2Namespace", "SF_PARAM2NS_DESC");
        
        // Finish up the page definition
        setControl(container);
        setPageComplete(true);        
    }
}    

SimpleFilterPage Methods
There are four important interface methods that must be implemented in this class:

Method Description
public SimpleFilterPage() The constructor performs some basic initialization, such as setting a unique ID for the page and setting the title and description for the page. The text representing the page title and description are kept in the resources.properties file so that they can be localized or customized easily, if necessary.
public String getHelpID() This method is called by the Policy Studio help system. There is a Help button on every configuration page in the Policy Studio. When this button is pressed, the help system is invoked. Every page has a help ID (for example, simple.help) associated with it, which is mapped to a help page. This mapping is defined in the /plugins/com.vordel.rcp.policystudio.resources_(version ...)/contexts.xml file under the directory where you have installed Policy Studio, for example:

                  <context id="simple_help">
                    <description>>Simple filter test</description>
                    <topic label="Simple Filter" href="html/common/tutorials/general_filter.html"/>
                  </context>


Please note a dot in a help ID is replaced by underscore in the contexts.xml file as in the example above. All URLs specified in the contexts.xml file are relative from the /plugins/com.vordel.rcp.policystudio.resources_(version ...) folder of your Policy Studio installation. You can add the lines from the example above to the contexts.xml file now, and you will check that the help page works at the end of this tutorial.
public boolean performFinish() This method gives you the chance to process the user-specified data before it is submitted to the Entity Store. For example, any validation on the data should be added to this method.
public void createControl(Composite parent) This method is responsible for creating and ordering the input fields on the configuration page. Again, localization keys from the resource.properties file are used to give labels for the input fields. It is important to note that the createTextAttribute takes a String as its second parameter, which corresponds to a field defined for an entity (for example, param, param1Namespace, param2, and param2Namespace are all defined in the SimpleFilter entity type. When the user submits the values entered in these fields, the values are set to the corresponding fields in the entity instance in the Entity Store.

resources.properties File
Both the SimpleFilterUI and the SimpleFilterPage classes use localized keys for all text that is displayed on the configuration screen. This makes it a trivial task to localize or customize all text that is displayed in the Policy Studio. The localization keys and their corresponding strings are stored in the resources.properties file, which takes the following format:

# Palette category for example filters
FILTER_GROUP_EXAMPLE=Example Filters

# Title and Description for the SimpleFilter 
SIMPLE_PAGE=Simple Filter Configuration
SIMPLE_PAGE_DESCRIPTION=Configure parameter values for the Simple Filter

#
# Field labels and descriptions
#
SF_NAME=Filter Name:
SF_NAME_DESC=The name of the Simple Filter
SF_PARAM1=Parameter 1
SF_PARAM1_DESC=the first parameter
SF_PARAM1NS=Parameter 1 Namespace
SF_PARAM1NS_DESC=the first parameter namespace field
SF_PARAM2=Parameter 2
SF_PARAM2_DESC=the second parameter
SF_PARAM2NS=Parameter 2 Namespace
SF_PARAM2NS_DESC=the second parameter namespace field    

The final resource is the simple.gif image file, which is displayed as the icon for the SimpleFilter in the Policy Studio. You can see this icon a little later in this tutorial when you configure the SimpleFilter.

Now that all classes and resources have been written, it is now time to build the relevant JAR files and incorporate them into the product.


Step 5: Build Classes

The following steps must be performed to build the Java classes (and resources) described in the previous sections. Note that the classes must be built against a 1.6 JDK because this is used to build the Enterprise Gateway, which contains the Oracle API JAR files. A manifest file is required, which enables the GUI components to be visible to the Policy Studio classloader. For a reference, see the sample MANIFEST.MF file included in the example.

  • Build classes and associated resources into a JAR file using your chosen build technology.
  • Place the new JAR in the GW_HOME/ext/lib directory, where GW_HOME refers to the root of your Enterprise Gateway installation.
  • Place the new JAR in the PS_HOME/plugins directory, where PS_HOME refers to the root of your Policy Studio installation.
  • Place any third-party JAR used by your classes into the GW_HOME/ext/lib and into the PS_HOME/plugins directories.
  • Restart both the server and the Policy Studio.

As an example of one way to build the SimpleFilter classes, an Ant build file, called build.xml, is supplied in the /example/filter directory of the Enterprise Gateway installation. More detailed instructions on how to build this example are found in the Build the Oracle Enterprise Gateway Example page.

The Ant file builds the SimpleFilter classes and packages all associated resources into the VordelExampleFilters.jar file. This file must then be placed in the GW_HOME/ext/lib folder and the PS_HOME/plugins folder as outlined above.

When both the server and the Policy Studio boot up, they automatically pick up the new JAR file. In the remaining steps of this tutorials, you can see how to configure a policy that includes the SimpleFilter and then test its functionality.


Step 6: Load TypeDocs

You must now register the type definition for the SimpleFilter with the Entity Store using the Policy Studio. When the entity type has been registered, it is guaranteed that any time the server needs to create an instance of the SimpleFilter, the instance contains the correct fields with the appropriate types.

Register using the Policy Studio
To register the type definition sing the Policy Studio, perform the following steps:

  1. Start the Policy Studio and connect to the Enterprise Gateway. The following screen is displayed:

    Policy Studio Dashboard

    Policy Studio Dashboard

  2. Click the Profile Management button beside the Process List on the left, and you should see a screen similar to the following:

    Profile Management

    Profile Management

  3. Create a copy of the active configuration. To do this, expand the Core Configurations tree node, and right-click the active configuration (for example, Default Configuration). Select Create via Copy in the context menu, and give the new configuration a meaningful name (for example, Custom Filter Config).
  4. Right-click the new configuration, and select Edit from the context menu. You are asked to enter a passphrase. If this has not been changed from the default, you can leave the field blank and proceed. This displays the Profile Editor tab with Custom Filter Config as a root node. Right-click this root node, and select Import Custom Filter Types from the menu.

    Import Custom Filter

    Import Custom Filter

  5. Browse to the location of the sampleTypeSet.xml file, which is located in the /filter directory of your Oracle Enterprise Gateway installation. A TypeSet file is used to group together one or more TypeDocs so that multiple TypeDocs can be added to the Entity Store in batch mode. The sampleTypeSet.xml file is displayed as follows:

    <typeSet>
        <!-- SimpleFilter TypeDoc -->
       <typedoc file="SimpleFilter.xml"/>
    </typeSet>    
    

  6. After selecting the TypeSet, the workspace refreshes. To verify that the filter is available, navigate to a pre-existing policy, and you should see the Example Filters category in the palette, with the filters contained inside.

    Verify Filter Install

    Verify Filter Install

  7. Right click the configuration, and commit this version. From now on, any further revisions of this version, or configurations copied from this configuration contain the new filter types.
  8. Click the Deployment Details tab on the Dashboard, and select the running process and the core configuration. You can now deploy the new Custom Filter Config with the latest version containing the new types.
  9. Click the Deploy button at the bottom right of the screen.

Verifying using the Entity Explorer
Another way to verify that your new filter has been installed is to use the Entity Explorer. You can use the Entity Explorer tool for browsing the entity types and entity instances that have been registered with the Entity Store.

To verify that the filter has been installed, perform the following steps:

  1. Start the Entity Explorer from the /bin directory of your installation using the esexplorer startup script. The Entity Explorer is displayed as follows:

    Entity Explorer

    Entity Explorer

    There are two main tabs on the Entity Store's interface: Entities and Types. The Types tab lists all currently defined entity types that have been registered with the Entity Store, while the Entities tab lists all the instances of entities that have been committed to the Entity Store (for example, configured filters).
  2. You must first point the Entity Explorer at the management interface exposed by a running instance of the Enterprise Gateway. Right-click the Entity Stores node in the Entity Hierarchy tree:

    Connecting to an Entity Store

    Connecting to an Entity Store

    The Connect to an Entity Store dialog is displayed as follows:

    Connect to an Entity Store

    Connect to an Entity Store

  3. The Enterprise Gateway exposes a management service that interfaces to the underlying Entity Store. This is the preferred method of managing the Entity Store. You can now start the Enterprise Gateway (which connects to the Entity Store), and point the Entity Explorer at the management service exposed by the Enterprise Gateway. Start the Enterprise Gateway from the /bin directory of your product installation.
  4. You can now configure the Entity Explorer to talk to the management service exposed by the Enterprise Gateway. By default, this service is available at the following URL, where HOST refers to the host name or IP address of the machine on which the Enterprise Gateway is running:
    http://HOST:8090/configuration/policies.
  5. Enter this address in the URL field of the Connect to an Entity Store dialog. If you have not already changed the default username and password for the entity store, use the default username admin with password changeme. Otherwise, specify the alternative username and password in the fields provided. Click OK to connect to the management service on the Enterprise Gateway. A log message is displayed in the Log panel at the bottom right corner of the screen to confirm that you are connected to the Enterprise Gateway at the specified URL.
  6. Expand the Entity Store filename, and then expand the System Components node to display the list of entity instances stored in the Entity Store:

    Instances of Entities Stored in the Entity Store

    Instances of Entities Stored in the Entity Store

  7. Click the Types tab, expand the node representing the Enterprise Gateway's management interface, (for example, http://my_host:8090/configuration/policies), and expand the Entity node to display the list of registered entity types. Each of these entity types has a corresponding type definition. Expand the Filter node, and click the SimpleFilter entity type in the tree. The names and data types of the fields for this entity type can be seen under the Details tab on the right of the Entity Explorer. To view the type definition for this entity, click the XML tab. These details should match the filter that has just been added.

    SimpleFilter Loaded in the Entity Store

    SimpleFilter Loaded in the Entity Store

The Entity Store is now aware of the SimpleFilter type. You can now create an instance of a Filter class that encapsulates the fields defined in the SimpleFilter type.

The remaining steps in this tutorial show how to configure a policy that includes the SimpleFilter, and then tests its functionality.

Step 7: Construct a Policy

This section first shows how to build a simple policy that echoes messages back to the client. The next step then adds the SimpleFilter to the policy.

You can build policies using the Policy Editor in the Policy Studio. To build a policy, you can drag message filters from the filters palette on the left on to the policy canvas on the right. You can then link these filters using success or failure paths to create a network of filters. The following screenshot shows the Policy Editor screen:

Circuit Editor

Circuit Editor

The policy canvas is the large blank area on the screen, while the filters palette is the area on the right that contains the filters. Message filters are grouped together by category (for example, all the content-based filters are displayed together in one group, while all the authentication filters are displayed in a different group). You can build policies by dragging these filters and dropping them on to the canvas.

Important Note:
If you have followed the steps outlined above, you can see a new category of filters nameed Example Filters in the filter palette. The Example Filters category is expanded in the example screenshot.

Creating the Policy
To create a policy, peform the following steps:

  1. Right-click Policies in the tree view to the left of the Policy Studio, and select Add Policy. Enter Circuit 1 as the name of the new policy in the Policy dialog.
  2. This example creates a policy containing only one filter: the Reflect filter. This filter simply echoes the client message back to the client. The Reflect filter is found in the Utility filter group. Drag this filter on to the editor.
  3. Enter a name for the filter (or use the default) in the field provided. Select the default value (200) for the HTTP response status code, and click Finish. The policy needs to have a start filter, so right-click the Reflect filter, and choose Set as Start.
  4. You must now configure the Process to invoke the new policy. On the Services tab in Policy Studio, select the Process (for example Enterprise Gateway) -> Default Services. Right-click Path: /, and select Edit.
  5. Enter the following values on the Configure Relative Path dialog:
    • Relative Path:
      Keep / in this field, meaning that the Process invokes the policy selected below for all requests received on this path.
    • Policy:
      Select Circuit 1 to configure the server to send all requests received on the path configured above to our newly configured policy.
  6. To force the server to pick up the new configuration, you must deploy the configuration to the server. Click the Deploy or press F6.
  7. To test this, start up the Service Explorer testing tool (distributed separately):

    Test Client

    Test Client

  8. Assuming your HTTP interface is listening on port 8080, you can configure Service Explorer to send a request to: http://HOST:8080/, where HOST is the hostname or IP address of the machine on which the server is running. Note that you send to / because, earlier, you configured the firewall to filter requests received on this relative path.
  9. Copy any SOAP message into the Request panel of Service Explorer. Click the triangular green Send button to send the message to the server, which echoes it back to the client using the Reflect filter configured earlier. When the message has been returned to Service Explorer, try changing the message slightly to assure yourself that the correct message is actually being returned.

Finally, it is time to add the SimpleFilter to the policy, and to test its functionality.

Step 8: Configure the SimpleFilter

The final section of this tutorial adds the SimpleFilter to the policy built in the previous section. Currently, the policy consists of only one filter, the Reflect filter:

Circuit 1 Example

Circuit 1 Example

The SimpleFilter is found in the Example Filters category of the Filter Palette on the Policy Studio.

Example Filters Category

Example Filters Category

Configuring the Filter
To configure the new filter, perform the following steps:

  1. Drag and drop the SimpleFilter on to the policy canvas. The configuration screen is displayed as follows:

    Simple Filter

    Simple Filter

  2. Because the type definition for the SimpleFilter entity contained default values, the input fields on the configuration screen are pre-populated with these default values.
  3. Before completing the configuration, make sure the help system is working correctly. Remember that in Step 4 of this tutorial, you added a mapping to the contexts.xml file (in the /plugins/com.vordel.rcp.policystudio.resources_(version ...) folder of your Policy Studio installation.) If you have not done so yet, this is explained in Step 4. After restarting Policy Studio, you can try clicking the Help button while editing the SimpleFilter configuration.
  4. Right-click the Simple node, and select Set as Start from the context menu. Connect the Simple node to the Reflect node with a success path. You can do this by clicking the Success Path arrow, and then clicking the Simple node, followed by clicking the Reflect node. The policy is now displayed as follows:

    Policy with SimpleFilter and Reflect

    Policy with SimpleFilter and Reflect

  5. To force the server to pick up the new configuration, you must refresh the server. Click the Deploy button in Policy Studio (or press F6).
  6. You can now test the configuration to make sure that it performs as expected (that it can correctly add the two numbers together). Load the appropriate SOAP message into the Service Explorer by selecting the File -> Samples -> Add two numbers menu option. The following SOAP message is loaded:

    <soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
                   xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
                   xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
      <soap:Body>
        <Add xmlns="http://startvbdotnet.com/web/">
          <a>1</a>
          <b>2</b>
        </Add>
      </soap:Body>
    </soap:Envelope>  
    

Important Note
Note the presence of the <a> and <b> elements in the SOAP message, and the namespace declaration in the <Add> element. These elements and their corresponding namespaces match the values configured in the SimpleFilter earlier.

Make sure to send the message to the same address as before by entering http://localhost:8080/ as the URL. The Wsdl field is not needed and can be removed. Press the Run (Send) button when you have done this to send the message to the server.

The following response is returned to Service Explorer:

<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
               xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance\" 
               xmlns:xsd="http://www.w3.org/2001/XMLSchema"> 
  <soap:Body>
    <AddResponse xmlns="http://startvbdotnet.com/web/"> 
      <AddResult>3</AddResult>
    </AddResponse>
  </soap:Body>
</soap:Envelope>

The value of the <AddResult> element is 3, which indicates that the newly added filter has worked successfully.

Conclusion

This tutorial described a working example of how to write a message processing filter using the Oracle Enterprise Gateway and how to integrate it into a policy. You should now try to build your own filter by following a similar sequence of steps to those outlined in this tutorial.

If you have any queries on the content of this document, please contact the Support Team with your questions.