Oracle9i Application Server Wireless Edition Developer's Guide Release 1.1 Part Number A86700-01 |
Library | Service | Contents | Index

# 2
Creating Adapters

This document describes how to create and manage Java classes that implement Wireless Edition adapters. Each section of this document presents a different topic. These sections include:

- Section 2.1, "What Is a Wireless Edition Adapter?"

- Section 2.2, "Creating Adapters"

- Section 2.3, "Importing an Adapter into the Repository"

- Section 2.4, "HelloAdapter Source Code"

## 2.1 What Is a Wireless Edition Adapter?

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

### 2.1.1 Using Wireless Edition Adapters

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

The Wireless Edition provides adapters that retrieve any content, including Web, database, and spatial content. The Oracle9i Application Sever Wireless Edition Implementation Guide describes the adapters provided by the Wireless Edition, and explains how to create services that use them.

### 2.1.2 Implementing Wireless Edition Adapters

You create your own Java adapters for the Wireless Edition by implementing the `RuntimeAdapter` 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 the Wireless Edition. The adapter that you create must simply expose the entry points and return the value types that the Wireless Edition expects.

### 2.1.3 Adapter Content Formats

Adapters return content that conforms to a Wireless Edition content DTD. The returned content can be in one of the following formats:

- SimpleResult

- AdapterResult

In most cases, adapters return content that conforms to the SimpleResult DTD. The SimpleResult DTD contains elements that represent the components of an abstract user interface, such as tables, text, forms, and menus.

Adapters can also return content in the AdapterResult format. The AdapterResult format is an intermediary, user interface-independent content format. You can use it to pass raw data between Wireless Edition components, such as chained services.

Since device transformers operate only on the SimpleResult format, a ResultTransformer associated with a master service must convert an AdapterResult document to the SimpleResult format before the content can be delivered.

Note: The target attributes in the SimpleResult XML that is returned by the adapter should not be URL encoded. However, the target attributes in the SimpleResult XML document, which are fetched by the URL Adapter (either the built-in adapter or a modified version of it) should be URL encoded.

## 2.2 Creating Adapters

Generally, an adapter performs the following functions:

1. Connects to a data source.

2. Retrieves content.

3. Converts the content to a Wireless Edition XML format.

The adapter should know the content source format and how to map it to a Wireless Edition results format.

Follow these rules to create an adapter:

1. Implement the `oracle.panama.rt.RuntimeAdapter` interface.

2. Provide an empty, default constructor.

3. Make the class thread-safe.

4. Implement the following methods in the `RuntimeAdapter` interface:

   - `init()`

   - `invoke()`

   - `getInitArguments()`

   - `getInputArguments()`

   - `getOutputArguments()`

   - `destroy()`

The master service calls the `init()` function once, the first time the adapter is invoked. The `init()` function performs initialization functions for the adapter. The master service calls the `invoke()` function every time the adapter is invoked.

The `getInitArguments()`, `getInputArguments()`, and `getOutputArguments()` methods enable the Wireless Edition to create an adapter definition for an adapter. The `getInitArguments()` method gets the initialization arguments for the MasterService and returns the arguments or null if no arguments exist. The `getInputArguments()` method gets the input arguments for the MaterService. The `getOutputArguments()`method gets the output arguments for the MasterService. The `destroy()` method destroys the provider, thereby releasing the resources that were implemented by the adapter.

The Wireless Edition calls the methods in the following order:

1. Default constructor

2. `getInitArguments()`

3. `init()`

4. `getInputArguments()`

5. `getOutputArguments()`

6. `invoke()`

7. `destroy()`

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

### 2.2.1 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.

The complete source code for the sample appears in Section 2.4, "HelloAdapter Source Code".

The reference numbers in brackets that appear in the discussion refer to the corresponding section in the complete listing of the source code.

Sample: HelloAdapter

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

When invoked, the adapter returns these XML elements which conform to the SimpleResult DTD:

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

The following sections describe each method in the sample adapter.

#### 2.2.1.1 init()

The `init()` method initializes the adapter. Every adapter in the Wireless Edition must implement an `init()` method. The Wireless Edition 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 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. The RuntimeAdapterHelper class contains methods for creating input arguments and output arguments. Following initialization, the `createArguments()` and the `createOutputArguments()` methods are called out. They return the input arguments and the output arguments as follows:

    Public void init (Arguments args) throws AdapterException {  [3]
        synchronized (this) {
            initialized = true;
           greeting = args.getInputValue ( GREETING );
        }
    }

#### 2.2.1.2 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 `ServiceContext`. It returns an XML element that holds the result. See the source code section with the reference number [4] in the complete source code listing for HelloAdapter in Section 2.4, "HelloAdapter Source Code".

Upon receiving an end user request, the Wireless Edition Request Manager creates a `ServiceContext` object. The `ServiceContext` contains any parameter values specified by the user, service alias, or master service. The `ServiceContext` 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(doc, "SimpleResult");

Then, it creates the container element:

    Element container = XML.makeElement(result, "SimpleContainer");
            result.appendChild (container);

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

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

As defined in the SimpleResult 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(st, "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.getInputArguments().getInputValue( NAME );
      Text txt = XML.makeText(sti, greeting + " " + name + "!");
      sti.appendChild (txt);
      return result;

#### 2.2.1.3 getInitArguments()

Every adapter must implement `getInitArguments()`. This method enables a master service to determine the initialization parameters that are used by the adapter.

The `RuntimeAdapter` class encapsulates the adapter parameters. In the `getInitArguments()`method, you get the initialization parameters in the `Adapter` object and return the initialization arguments.

The numbers in bold that appear on the right side of the source code excerpts below refer to where the excerpt is located within the complete source code listing in Section 2.4, "HelloAdapter Source Code".

    private Arguments initArgs = null;            [5]
    public Arguments getInitArgument() throws AdapterException {
      if (initArgs == null) {
          synchronized (this) {
            if (initArgs == null) {
                initArgs = RuntimeAdapterHelper.createArguments();
                // Any init parameters would be set here..
                Argument initArg = initArgs.createInput(GREETING, "Greeting phrase",
    null, true );
                        initArg.setType(ArgumentType.SINGLE_LINE);

            }
          }
      }
      return initArgs;
    }

#### 2.2.1.4 getInputArguments()

    private Arguments inputArgs = null;           [6]
    public Arguments getInputArguments()  throws AdapterException{
      if (inputArgs == null ) {
          synchronized (this) {
            if (inputArgs == null) {
                inputArgs = RuntimeAdapterHelper.createArguments();
                Argument inputArg = inputArgs.createInput(NAME, "Name to greet",
    null ,true);
                        inputArg.setType(ArgumentType.SINGLE_LINE);
            }
          }
      }
      return inputArgs;
    }

#### 2.2.1.5 getOutputArguments()

    private OutputArguments outputArgs = null;              [7]
    public OutputArguments getOutputArguments()  throws AdapterException{
            if (outputArgs == null) {
               synchronized (this) {
                   outputArgs = RuntimeAdapterHelper.createOutputArguments();
               }
            }
            return outputArgs;
       }

       public void destroy() { }

    }

### 2.2.2 Managing Arguments

The Wireless Edition 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.

#### 2.2.2.1 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.

#### 2.2.2.2 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();
    ...

## 2.3 Importing an Adapter into the Repository

After you create and compile the class that implements the adapter, you import the adapter into the Wireless Edition 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 Oracle9i Application Server Wireless Edition 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. Start the Service Designer.

2. Right-click Adapters in the Service Designer Repository tree view.

3. Click Create New Adapter. The Create New Adapter dialog box appears.

#### Figure 2-1 Create New Adapter

Text description of the illustration adapter1.gif

1. Fill in the fields for each parameter. Select the box next to Valid to specify that the adapter is available to services. If the box is not selected (that is, if the adapter is invalid), then the adapter is unavailable, and all master services that use the adapter are invalid.

The form includes the following parameters:

Table 2-1 Adapter 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.

### 2.3.1 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 Service Designer repository tree view.

2. Right-click the adapter and click Delete.

### 2.3.2 Modifying Adapters

To modify an adapter:

1. Select the adapter in the Service Designer repository tree view. The General tab of the properties panel appears in the right frame.

2. Modify the parameters and click Apply.

## 2.4 HelloAdapter Source Code

The complete source code for HelloAdapter is listed below. Each section of the code is numbered on the right side of the text (for example, `[1]`) to assist in mapping the description in Section 2.2.1, "Sample Adapter Class" to the source code in its entirety.

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

    package sampleadapter;
    import org.w3c.dom.Element;                                 [1]
    import org.w3c.dom.Document;
    import org.w3c.dom.Text;

    import oracle.panama.Argument;
    import oracle.panama.Arguments;
    import oracle.panama.OutputArguments;
    import oracle.panama.ArgumentType;
    import oracle.panama.rt.ServiceContext;
    import oracle.panama.adapter.RuntimeAdapter;
    import oracle.panama.adapter.AdapterException;
    import oracle.panama.adapter.RuntimeAdapterHelper;
    import oracle.panama.core.util.XMLUtil;
    import oracle.panama.core.xml.XML;

    public class HelloAdapter implements RuntimeAdapter {        [2]

        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 { [3]
            synchronized (this) {
                initialized = true;
    	          greeting = args.getInputValue( GREETING );
            }
        }

        /**                                                         [4]
         *  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 (ServiceContext sr) throws AdapterException {

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

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

            // Create SimpleContainer element
            Element container = XML.makeElement(result, "SimpleContainer");
            result.appendChild(container);

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

                                                        Sample");
            container.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.getInputArguments().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 Arguments initArgs = null;     [5]
    public Arguments getInitArguments() throws AdapterException {
      	if (initArgs == null) {
    	      synchronized (this) {
    		        if (initArgs == null) {
    		            initArgs = RuntimeAdapterHelper.createArguments();
    		            // Any init parameters would be set here..
    		           Argument initArg = initArgs.createInput(GREETING, "Greeting phrase",

                                                   null, true );
                           initArg.setType(ArgumentType.SINGLE_LINE);

    		             }
    	           }
           }
           	return initArgs;
        }

        private Arguments inputArgs = null;       [6]
        public Arguments getInputArguments()  throws AdapterException{
    	      if (inputArgs == null ) {
    	          synchronized (this) {
    		            if (inputArgs == null) {
    		                inputArgs = RuntimeAdapterHelper.createArguments();
    		               Argument inputArg = inputArgs.createInput(NAME, "Name to greet",

                                                         null ,true);
                          inputArg.setType(ArgumentType.SINGLE_LINE);
                		}
    	          }
    	      }
    	      return inputArgs;
        }

        private OutputArguments outputArgs = null;  [7]
        public OutputArguments getOutputArguments()  throws AdapterException{
            if (outputArgs == null) {
               synchronized (this) {
                   outputArgs = RuntimeAdapterHelper.createOutputArguments();
               }
            }
            return outputArgs;
        }

        public void destroy() { }

    }

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