Oracle Portal-to-Go Implementation Guide Release 1.0.2.2 A86635-02 |
Library | Service | Contents | Index

# 9
Adapters

This document describes how to create and manage Java classes and stylesheets that implement Portal-to-Go adapters. Topics include:

- What Is a Portal-to-Go Adapter?

- Creating Adapters

- Importing an Adapter into the Repository

- Extending the Stripper Adapter

## What Is a Portal-to-Go Adapter?

A Portal-to-Go adapter is a Java application that retrieves data from an external source and renders it in Portal-to-Go XML. When invoked by a master service, an adapter returns an XML document that contains the service content.

In the Portal-to-Go architecture, adapters constitute the interface between the Portal-to-Go server and the content source.

Portal-to-Go adapters primarily return content. But they can also perform other functions. For example, the Provisioning adapter, which is included in the Portal-to-Go initial repository, manages Portal-to-Go users. You can use it to create, remove, and modify users.

### Using Portal-to-Go Adapters

To use a Portal-to-Go adapter, you create a master service that invokes the adapter. Master services encapsulate the primary Portal-to-Go functionality; they make information and applications available to the end users.

Portal-to-Go provides adapters that retrieve Web and database content. Chapter 5, "Portal-to-Go Services" describes the adapters provided by Portal-to-Go, and how to create services that use them.

### Implementing Portal-to-Go Adapters

You create your own Java adapters for Portal-to-Go by implementing the `Adapter` interface. The adapter you create can be simple or very complex. It can be a self-contained application or, as in the case of the Web Integration adapter, it can invoke external applications. How the adapter retrieves information is transparent to Portal-to-Go. It must simply expose the entry points and return the value types that Portal-to-Go expects.

### Content Formats

Adapters return content that conforms to a Portal-to-Go content DTD. In most cases, adapters return content that conforms to the Simple Result DTD. The Simple Result DTD contains elements that represent the components of an abstract UI, such as tables, forms, and menus.

Adapters can also return content in Adapter Result format. Adapter Result format is a intermediary, user interface-independent content format. You can use it to pass raw data between Portal-to-Go components, such as chained services. Since device transformers operate only on Simple Result format, a result transformer associated with a master service must convert an Adapter Result document to Simple Result format before the content can be delivered.

For more information on Portal-to-Go XML, see Chapter 8, "Working with Portal-to-Go XML."

## Creating Adapters

Generally, an adapter performs the following functions:

1. Connects to a data source.

2. Retrieves content.

3. Converts the content to a Portal-to-Go XML format.

The adapter should know the content source format and how to map it to a Portal-to-Go results format.

Follow these rules to create an adapter:

1. Implement the `Adapter` interface.

2. Provide an empty, default constructor.

3. Make the class thread-safe.

4. Implement the following methods in the `Adapter` class:

   - `init()`

   - `invoke()`

   - `getInitDefinition()`

   - `getAdapterDefinition()`

The master service calls the `init()` function once, the first time the adapter is invoked. The `init()` function should perform initialization functions for the adapter. The master service calls the `invoke()` function every time the adapter is invoked. The `getInitDefinition()` and `getAdapterDefinition()` methods enable Portal-to-Go to create an adapter definition for an adapter.

Portal-to-Go calls the methods in the following order:

1. Default constructor

2. `getInitDefinition()`

3. `init()`

4. `getAdapterDefinition()`

5. `invoke()`

The `invoke()` method is then called again every time the adapter is invoked.

### Adapter Definition

An adapter definition defines the parameters used by an adapter. To create an adapter definition, you instantiate the `AdapterDefinition` interface. Each adapter has two adapter definitions: one for the input parameters required to initialize the adapter, and one for all adapter parameters--initializing, runtime, and output.

To make its parameters available to master services, each adapter must implement the following methods.

Method | Description
--- | ---
`getInitDefinition()` | This method should return the initial `AdapterDefinition` object, which defines the parameters required to intialize the adapter.
`getAdapterDefinition()` | This method can only be called on an initialized adapter. It should return the complete `AdapterDefinition` object, which defines the initial, input, and output parameters.

### Sample Adapter Class

The following sample Java class is a complete, but minimal, adapter implementation. It greets a user by name. It takes a single initialization parameter, the string used for the greeting, and a single input parameter, the name of the user.

    // Copyright (c) 1999, 2000 by Oracle Corporation, all rights reserved.
    //
    // Title:  HelloAdapter
    // Usage:  Demonstrate Panama Adapter with init/input parameters

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

    import oracle.panama.Argument;
    import oracle.panama.Arguments;
    import oracle.panama.ArgumentType;
    import oracle.panama.ServiceRequest;
    import oracle.panama.adapter.Adapter;
    import oracle.panama.adapter.AdapterDefinition;
    import oracle.panama.adapter.AdapterException;
    import oracle.panama.adapter.AdapterHelper;
    import oracle.panama.core.util.XMLUtil;
    import oracle.panama.core.xml.XML;

    public class HelloAdapter implements Adapter {

        private boolean initialized = false;

        /** Greeting phrase, default is Hello */
        private String greeting = "Hello";

        /** Init parameter name for the greeting phrase */
        public static final String GREETING = "greeting";

        /** Input parameter name for the name to greet */
        public static final String NAME = "name";

        /** This is the initialization method, called once when the adapter
         *  is instantiated for the very first time. Whatever you do here
         *  should be synchronized to ensure that things are not initialized
         *  twice.
         *  @param args The parameters needed for initialization
         */
        public void init (Arguments args) throws AdapterException {
            synchronized (this) {
                initialized = true;
    	    greeting = args.getInputValue( GREETING );
            }
        }

        /**
         *  This is the main request handler, invoked each time a client makes
         *  a request. This is a simple example that is capable of returning
         *  output according to Portal-to-Go simpleresult.dtd.
         *  @param sr The ServiceRequest object
         *  @return Element The XML element holding the result
         *  @exception Exception Not used here.
         */
        public Element invoke (ServiceRequest sr) throws AdapterException {

            // This adapter returns this XML element:
            //    <SimpleResult>
            //       <SimpleText title="Oracle Portal-to-Go Server Hello Sample">
            //          <SimpleTextItem name="message" title="Portal-to-Go says:">
            //             <greeting> <name>!
            //          </SimpleTextItem>
            //        </SimpleText>
            //    </SimpleResult>

            // Create result element
            Document doc = sr.getOwnerDocument();
            Element result = XML.makeElement(doc, "SimpleResult");

            // Create SimpleText element
            Element st = XML.makeElement(result, "SimpleText");
            st.setAttribute ("title", "Oracle Portal-to-Go Server HelloAdapter
    Sample");
            result.appendChild (st);

            // Create SimpleTextItem element
            Element sti = XML.makeElement(st, "SimpleTextItem");
            sti.setAttribute ("name", "message");
            sti.setAttribute ("title", "Portal-to-Go says:");
            st.appendChild (sti);

            // Create actual text
    	String name = sr.getArguments().getInputValue( NAME );
            Text txt = XML.makeText(sti, greeting + " " + name + "!");
            sti.appendChild (txt);

            return result;
        }

        // The following method is required. If there are any initialization
        // parameters for this adapter they would be set here.
        private AdapterDefinition initDef = null;
        public AdapterDefinition getInitDefinition() {
    	if (initDef == null) {
    	    synchronized (this) {
    		if (initDef == null) {
    		    initDef = AdapterHelper.createAdapterDefinition();
    		    // Any init parameters would be set here..
    		    initDef.createInit( ArgumentType.SINGLE_LINE, GREETING, "Greeting phrase",
    null );
    		}
    	    }
    	}
    	return initDef;
        }

        private AdapterDefinition adpDef = null;
        public AdapterDefinition getAdapterDefinition() throws AdapterException {
    	if (adpDef == null ) {
    	    synchronized (this) {
    		if (adpDef == null) {
    		    if (initDef == null)
    			throw new AdapterException ("Adapter is not properly initialized");
    		    adpDef = initDef;
    		    adpDef.createInput( ArgumentType.SINGLE_LINE, NAME, "Name to greet", null );
    		}
    	    }
    	}
    	return adpDef;
        }

        public static void main(String[] arg) {
            oracle.panama.core.util.Locator.getInstance();
            System.out.println("Start HelloAdapter");
            HelloAdapter ha = new HelloAdapter();
            Arguments args = oracle.panama.core.csc.CSCFactory.makeArguments();
            try {
    	    args.setInputValue( GREETING, "Hey" );
                AdapterDefinition ad = ha.getInitDefinition();
                System.out.println("InitDefinition:\n" + ad);
                ha.init(args);
                ad = ha.getAdapterDefinition();
                System.out.println("AdapterDefinition:\n" + ad);
    	    args.setInputValue( NAME, "Joe" );
    	    ServiceRequest sr =
    oracle.panama.core.csc.CSCFactory.makeServiceRequest(null, args);
    	    Element result = ha.invoke(sr);
                System.out.println("Result:\n" + XMLUtil.valueOf(result));
            } catch (Exception ex) {
                System.out.println("Exception " + ex.getMessage());
                ex.printStackTrace();
                ((oracle.panama.PanamaException)ex).getDetail().printStackTrace();
    	    System.exit(-1);
            }
            System.out.println("Exit HelloAdapter");
    	System.exit(-1);
        }
    }

When invoked, the adapter returns this result:

    <SimpleResult>
       <SimpleText title="Oracle Portal-to-Go Server Hello Sample">
          <SimpleTextItem name="message" title="Portal-to-Go says:">
             <greeting> <name>!
          </SimpleTextItem>
       </SimpleText>
    </SimpleResult>

The following sections describe each method in the sample adapter.

#### init()

The `init()` method initializes the adapter. Every adapter in Portal-to-Go must implement an `init()` method. Portal-to-Go calls the initialization method once, when the adapter is first instantiated.

The `init()` method takes an argument of type `Arguments`. `Arguments` is a convenience class for passing arguments. It includes various methods for setting and retrieving argument values. If invoked without an `Argument` object, `init()` throws an `AdapterException`. The sample `init()` method retrieves the initialization parameter value, the form of greeting, by calling `args.getInputValue()`. It passes the form of the greeting to the method, as the parameter `GREETING`. The default greeting set by the adapter is "Hello".

The contents of the initialization method must be synchronized to ensure that the class is not initialized again in another thread.

The sample sets the state variable, `initialized`, to true. Any adapter you create should similarly keep track of its own state. In a typical adapter implementation, the `init()` method would also contain logic for connecting to the content source.

#### invoke()

The `invoke()` method is the primary request handler. The master service calls this method every time a client makes a request. The adapter must be initialized before `invoke()` can be called.

The `invoke()` method takes an argument of type `ServiceRequest`. It returns an XML element that holds the result.

Upon receiving an end user request, the Portal-to-Go request manager creates a `ServiceRequest` object. The `ServiceRequest` contains any parameter values specified by the user, service alias, or master service. The `ServiceRequest` object also contains user information.

The sample `invoke()` builds a Simple Result document, using methods in the packages `org.w3c.dom.Element` and `org.w3c.dom.Text`. First, it creates the root result element:

    Element result = XML.makeElement("SimpleResult");

Next, it creates a `SimpleText` element, sets its title attribute, and appends the element to the root element:

    Element st = XML.makeElement("SimpleText");
    st.setAttribute ("title", "Oracle Panama Server HelloAdapter Sample");
    result.appendChild (st);

As defined in the Simple Result DTD, a `SimpleTextItem` is a required child element of `SimpleText`. The sample `invoke()` method creates a `SimpleText` element, sets its title attribute, and appends the element to the root element:

    Element sti = XML.makeElement("SimpleTextItem");
    sti.setAttribute ("name", "message");
    sti.setAttribute ("title", "Portal-to-Go says:");
    st.appendChild (sti);

It then retrieves the input parameter value, appends it to the result document, and returns the result to the caller, the master service:

    String name = sr.getArguments().getInputValue( NAME );
    Text txt = XML.makeText( greeting + " " + name + "!");
    sti.appendChild (txt);
    return result;

#### getInitDefinition()

Every adapter must implement `getInitDefinition()`. This method enables master services to determine the initialization parameters used by the adapter.

The `AdapterDefinition` class encapsulates adapter parameters. Your adapter should instantiate an `AdapterDefinition` object to hold the parameter definitions. In the `getInitDefinition()`method, you define the initialization parameters in the `AdapterDefinition` object and return the `AdapterDefinition`.

The method creates the initalization parameter with the following call:

    initDef.createInit( Argument.SINGLE_LINE, GREETING, "Greeting phrase", null );

The `createInit()` method has the following signature:

    public InitArgument createInit(int type,
                                   String parameterName,
                                   String comment,
                                   String[] options);

The following table describes the method's arguments:

Argument | Description
--- | ---
`type` | Defines the GUI input element used for the parameter in the Service Designer. Possible values: `SINGLE_LINE`: for a single-lined text field. `MULTI_LINE`: for a larger, multi-lined text field. `ENUM`: for a combo box with a drop-down list of possible parameter values.
`parameterName` | The name of the parameter.
`comment` | An optional comment for the parameter.
`options` | If using an enumeration list for the parameter, you specify the possible values in this argument. Otherwise, set this to `null`.

#### getAdapterDefinition()

`getAdapterDefinition()` defines the adapter's runtime input parameters. You should create an `AdapterDefinition` object to hold the input parameters. You use the `AdapterDefinition.createInput()` method to create input parameter definitions. This method is similar to `createInit()`. It has the following signature:

    public InputArgument createInput( int type,
                                      String parameterName,
                                      String comment,
                                      String[] options);

See "getInitDefinition()" for descriptions of each argument.

The `getInitDefinition()` method cannot be invoked on an uninitialized adapter. Therefore, the method first tests the adapter's state.

### Managing Arguments

Portal-to-Go provides the following interfaces for managing adapter arguments:

- `InitArgument`

- `InputArgument`

- `OutputArgument`

The interfaces implement the `Arguments` interface. They include methods for creating, setting, and retrieving arguments. You can use the `OutputArgument` interface to filter content returned by an adapter and to link adapter output to service input.

#### Filtering Adapter Output

By filtering adapter output, you can apply a test to the content returned by an adapter. This enables you to deliver a service to an end user only if the results of the service (particularly a service invoked as a scheduled job) meet a specified condition.

For example, an end user may want to check the price of a certain stock and receive a notification if the stock reaches a certain price. You can use output filtering to create a test on the results of the scheduled adapter invocation, and deliver the service only if the result meets a condition the user sets.

#### Filtering Adapter Output Sample Code

The following code shows how to use output filters. The sample assumes that an output filter has been defined for a column in the database content source.

    // Call provided API
    // Get the arguments from the ServiceRequest
    Arguments args = serviceRequest.getArguments();

    // Assume that we have created our own SimpleResult wrapper
    MySimpleResult simpleResult = new MySimpleResult();
    MySimpleResult notFoundResult = MySimpleResult.NOT_FOUND_MESSAGE;
    MyRow row;
    boolean match = true;
    int nRows = 0;
    MyResult result = <get the content ....>;

    while ((row = result.nextRow()) != null) {

       // Call provided API
       // only do this expensive op. if there is any filters defined.
       if (args.hasOutputFilters()) {
          match = true;
          for (int i = 0; i < row.getColumnCount(); i ++) {
             // Call provided API
             OutputArgument farg =
                args.getOutputArgument(row.getColumnName(i));
             if (farg != null &&
             !farg.compare(row.getColumnValue(i))) { // if any filtering
                                                    //   compare value.
                match = false;
                break;
             }
          }
       }
       if (match) { // only append row if it match the filtering.
          simpleResult.append(row);
          nRows ++;
       }
    }

    // Call provided API
    serviceRequest.setAnyResult(nRows !=  0); // Let the ServiceRequest
      // know if any result was fetched or not. This is used
      // by the notification component to determine if the
      // result should be sent or not.

    return nRows != 0 ? simpleResult.getElement() :
    notFoundResult.getElement();
    ...

## Importing an Adapter into the Repository

After you create and compile the class that implements the adapter, you import the adapter into the Portal-to-Go repository.

Note: You do not have to import an adapter into the repository if the adapter is in the CLASSPATH.

By importing the adapter into the repository, you make it available to master services. You use the Service Designer to import the adapter into the Portal-to-Go repository. Before importing the adapter, place the Java class in an archive, either a JAR or ZIP file, which you include in the system CLASSPATH.

You use the Create New Adapter form to install an adapter in the repository. To invoke the form:

1. Right-click Adapters in the Portal-to-Go Repository tree view.

2. Click Create New Adapter.

The form includes the following parameters:

Parameter | Value
--- | ---
Name | The name of the adapter. The name should be unique in the adapter folder.
Valid | Specifies whether the adapter is available to services. If selected, the adapter is available to services. If an adapter is invalid, the adapter is unavailable, and all master services that use the adapter are invalid.
Class Name | The Java class that either implements the adapter or serves as the entry point for the classes that implement the adapter.
Classes | The archived class or classes that implement the adapter. To import the archive, click Import and browse to the archive that implements the adapter.

### Deleting an Adapter

You can delete an adapter as follows. If you delete an adapter used by active services, the Service Designer flags the services.

To delete an adapter:

1. Select the adapter in the Portal-to-Go repository tree view.

2. Right-click the adapter and click Delete.

### Modifying Adapters

To modify an adapter:

1. Select the adapter in the Portal-to-Go repository tree view. The General tab of the properties panel appears in the right frame.

2. Modify the parameters and click Apply.

## Extending the Stripper Adapter

The stripper adapter dynamically retrieves content from a given URL and processes the markup tags in the content. Unlike the WIDL adapter, the stripper adapter does not require you to map the source page to output and input bindings in a WIDL file. Instead, the stripper adapter retrieves and processes arbitrary content.

After retrieving content, the stripper adapter calls a Java class to process the markup tags in the content. The stripper adapter locates the processing classes, or strip levels, that are available to it in the Strip.properties file. This file also contains proxy settings, which you must set to use the strip adapter.

Portal-to-Go provides two strip levels:

Level | Description | Implementing Class
--- | --- | ---
0 | Retains all tags in the content. | Strip0
1 | Strips all tags from the content. | Strip1

To customize markup processing, you can create you own strip levels. To create a strip level, you extend the `StripAbs` class. You then plug the strip level class into Portal-to-Go by referencing it in the Strip.properties file.

### Naming the Strip Level Class

You must name your strip level class as follows:

Strip n.java``

Where n is an integer representing the next available strip level. For example, given that Portal-to-Go provides strip levels 0 and 1, the first strip level you create should be level 2: Strip2.java.

### Required Methods in the Strip Level Class

The strip level you create must implement the following methods:

- `public String exec (String in)`

- `public int getLevel()`

The `exec()` method should process the content or invoke the logic that processes the content retrieved by the adapter. The `getLevel()` should simply return the strip level.

### Installing the Strip Level Class

Once you create and compile the strip level class, include it in the package `oracle.panama.adapter.stripper`.

Finally, include a reference to the strip level in the Strip.properties file. For example:

    //New strip level 3
    stripper.strip3 = oracle.panama.adapter.stripper.Strip3

| Copyright © 2000 Oracle Corporation. All Rights Reserved. |
Library | Service | Contents | Index