IBM Research
 

Porting WBI Plugins from 4.1 to 4.3

The WBI APIs have been updated as we have moved from WBI Development Kit for Java version 4.1 to version 4.3. (Version 4.2 was an internal-only release). We try to minimize changes to the API so that our users can avoid changing their plugins, but some improvements are necessary for (1) uniformity, simplicity, and ease of use, (2) infrastructure testing, and (3) abstraction of pluggable classes into interfaces.

This document explains the changes to the WBI API from version 4.1 to 4.3 and illustrates the necessary changes in the Demo Plugin to port it to the WBI Development Kit for Java 4.3.

WBI API Change Summary from 4.1 to 4.3
ClassChange
FetchUrl
  • A RequestEvent object must be passed as the first parameter of all fetch(...) calls. For MEGs, simply use the RequestEvent that was passed in with the handleRequest(...) method.
  • The fetch(...) method returns a ServiceResult object that can be used to access the resulting RequestInfo (which can be cast to a DocumentInfo for HTTP requests) and the MegInputStream that contains the resulting data.
HttpResponse
  • Some methods have been renamed for better naming consistency. The original methods are all there, but have been deprecated.
Packaging
  • The WBI classes have been moved into different packages with a simpler and more logical structure. A major improvement of the current packaging scheme is that a number of system-level classes and methods have been reduced to package scope so that we can avoid having too many public classes and methods that simply confuse things.
  • The import packages that most WBI programmers will need to use are:
    • com.ibm.wbi.*;
    • com.ibm.wbi.protocol.http.*;
    • com.ibm.wbi.protocol.http.beans.*;
    • com.ibm.wbi.util.*;
    • com.ibm.pvccommon.util.* (for Databases)
RequestEvent
  • the getRead() and getWrite() methods have been deprecated, preferring getMegInputStream() and getMegOutputStream(). This change removes the confusion over character vs. byte I/O.
Plugin
  • initialize(String) has been replaced with initialize(). The String was always empty. The original method still works, but was deprecated.
MEG Conditions
  • The rule syntax has been improved to have a more Java/C-like appearance. The basic form is field = value rather than the less-intuitive field value. Arbitrary levels of parentheses can be used. For more information, see the documentation for Meg.setCondition(java.lang.String).
  • Case sensitivity has changed. Use '=' for a case-sensitive comparison, e.g. to separate path=/foo from path=/Foo. Use '~' to ignore case, e.g. path~/foo will match /foo or /Foo or /FoO. Also beware that certain browser input is converted to lower-case before processing. For example, the server name part of the URL is converted to lower case so a browser request for http://MyServer/ will be seen internally as http://myserver. A condition of host=MyServer will fail but host=myserver or host~MyServer will match.
Database
  • moved from com.ibm.wbi.util package to com.ibm.pvccommon.util package
  • MissingRequiredResourceException must be caught when accessing Databases. This exception is not thrown under basic WBI configurations, but may result when using external databases to store WBI configuration information.
  • Database.createSection(...) has a new required second parameter. Use "" (an emptyString).

Example -- Porting the Demo Plugin

As an example of porting a simple plugin, here are the changes that were made to the Demo Plugin.

Imports

The WBI packages have been rearranged to group classes more consistently and to reduce the total number of packages.

Version 4.1

import com.ibm.wbi.io.MegInputStream;
import com.ibm.wbi.io.MegOutputStream;
import com.ibm.wbi.plugin.*;
import com.ibm.wbi.http.HttpHeader;
import com.ibm.wbi.http.FetchUrl;
import com.ibm.wbi.http.request.DocumentInfo;
import com.ibm.wbi.http.plugin.*;
import com.ibm.wbi.http.beans.AddPreambleEditor;
import com.ibm.wbi.http.beans.PageMovedGenerator;
import com.ibm.wbi.http.beans.StaticHtmlGenerator;
import com.ibm.wbi.http.beans.HtmlTemplateGenerator;

Version 4.3

import com.ibm.wbi.*;
import com.ibm.wbi.protocol.http.*;
import com.ibm.wbi.protocol.http.beans.*;

Plugin initialize(...)

The Plugin.initialize() no longer takes a parameter. Information needed by plugin initialization can be found with the Plugin.getSystemContext() method.

Version 4.1

public class demo extends HttpPlugin {
  ...
  public void initialize(String initData) {
    ...
  }
  ...
}

Version 4.3

public class demo extends HttpPlugin {
  ...
  public void initialize() {
    ...
  }
  ...
}

MEG Conditions

The conditions that determine when MEGs are involved in a transaction have been made to look more like normal Java/C syntax. There are also a few values such as %null% that have special meaning. There are both '=' (case sensitive) and '~' (non-case sensitive) operators.

Version 4.1

  public void initialize() {
    // A generator to say "Hello", 
    // either as a server at the path: "/" or
    // as a proxy at the URL: "//_demo/"
    StaticHtmlGenerator shg = new StaticHtmlGenerator();
    shg.setName( "helloWorld" );
    shg.setCondition( "(host null | host _demo) & 
                       path /" );
    shg.setPriority( 10 );
    shg.setStaticHtml( html );
    addMeg( shg );

    // now one for "/whoami"
    Generator whog = new WhoAmITheOldWay();
    whog.setName( "whoAmI" );
    whog.setCondition( "(host null | host _demo) &
                        path /whoami" );
    whog.setPriority( 10 );
    addMeg( whog );
    ...
  }

Version 4.3

  public void initialize() {
    // A generator to say "Hello", 
    //either as a server at the path: "/" or
    // as a proxy at the URL: "//_demo/"
    StaticHtmlGenerator shg = new StaticHtmlGenerator();
    shg.setName( "helloWorld" );
    shg.setCondition( "(host=%null% | host~_demo) & 
                       path=/" );
    shg.setPriority( 10 );
    shg.setStaticHtml( html );
    addMeg( shg );

    // now one for "/whoami"
    Generator whog = new WhoAmITheOldWay();
    whog.setName( "whoAmI" );
    whog.setCondition( "(host=%null% | host~_demo) & 
                        path=/whoami" );
    whog.setPriority( 10 );
    addMeg( whog );
    ...
  }

Accessing the MegInput/OutputStreams in a MEG

The getRead() and getWrite() methods have been deprecated, preferring getMegInputStream() and getMegOutputStream(). This change removes the confusion over character vs. byte I/O.

Version 4.1

    public void handleRequest( RequestEvent e ) 
       throws RequestRejectedException, IOException {
      ...
      // get the input stream
      MegInputStream is       = e.getRead();
      ...
      // the stream we write to
      MegOutputStream os = e.getWrite();
      ...
    }

Version 4.3

    public void handleRequest( RequestEvent e ) 
       throws RequestRejectedException, IOException {
      ...
      // get the input stream
      MegInputStream is       = e.getMegInputStream();
      ...
      // the stream we write to
      MegOutputStream os = e.getMegOutputStream();
      ...
    }

Using FetchUrl

FetchUrl is a utility class for accessing web resources either directly or through WBI's MEG chain. It has been changed in two ways:
  • A RequestEvent is needed to launch the fetch operation. Normally the MEG that needs to fetch a web resource just uses the same RequestEvent object that was passed to the MEG's handleRequest(...) method.
  • The fetch(...) method now returns a ServiceResult object that allows the caller to access the resulting RequestInfo and MegInputStream, which contain that result of the fetch operation.

Version 4.1

    public void handleRequest( RequestEvent e ) 
       throws RequestRejectedException, IOException {
      String getme = "http://www.yahoo.com/";
      MegInputStream mis;

      if (++count % 2 == 0) {
        mis = FetchUrl.fetch( getme );
      } else {
        mis = FetchUrl.fetchThroughProxy( e, getme );
      }

      // retrieve the response header from the 
      // fetched content and make
      // it our own response header
      // note: mis.getRequestInfo() is deprecated
      DocumentInfo di = (DocumentInfo) e.getRequestInfo();
      DocumentInfo mdi = (DocumentInfo) mis.getRequestInfo();
      di.setResponseHeader( mdi.getResponseHeader() );

      // copy the fetched content to our output stream
      e.getWrite().write( mis );
      // all done!
      e.getWrite().close();
    }

Version 4.3

    public void handleRequest( RequestEvent e ) 
       throws RequestRejectedException, IOException {
      String getme = "http://www.yahoo.com/";
      ServiceResult sr = null;

      if (++count % 2 == 0) {
        sr = FetchUrl.fetch( e, getme );
      } else {
        sr = FetchUrl.fetchThroughProxy( e, getme ); 
      }

      // retrieve the response header from the 
      // fetched content and make
      // it our own response header
      // note: mis.getRequestInfo() is deprecated
      DocumentInfo di = (DocumentInfo) e.getRequestInfo();
      DocumentInfo sdi = (DocumentInfo) sr.getRequestInfo();
      di.setResponseHeader( sdi.getResponseHeader() );

      // copy the fetched content to our output stream
      e.getMegOutputStream().write( sr.getMegInputStream() );
      // all done!
      e.getMegOutputStream().close();
    }