# Oracle9iAS Portal Developer Kit (PDK)
How to Build Portlets Using Web Services

Creation Date: | April 4, 2002
Status: | Production
Version: | PDK Release 2 (9.0.2 and later)

## Introduction

PDK-Java v2 provides an out-of-the-box service for invoking Web Services. It provides an abstraction to handle communication with web services. It allows you to declaratively invoke web services with the built-in web services renderer classes that it provides.

With PDK-Java, you can invoke both procedure-oriented RPC style web services as well as document-oriented Doc style web services. For DOC style services, the SOAP body carries a generic XML document, whereas in RPC style services, there's an explicit concept of "method invocation" coming into play. PDK-Java supports both these styles with specialized renderer classes.

The PDK-Java web service renderers are an extension to the basic portlet renderer framework designed to allow you to expose existing web services as portlets with the minimum of effort. By building on the same declarative portlet building approach that is used throughout the JPDK, the renderers provide a powerful way of "wiring in" almost any SOAP-based web service to Oraclie 9iAS Portal.

This document explains how you can build portlets using web services with the PDK-Java toolkit and its built-in renderers. For answers to frequently asked questions and background information read the W eb Services FAQ.

## Assumptions

- You have installed PDK-Java as described in the article Installing the PDK-Java Framework and samples

- You are familiar with portlet basics and the concept of a renderer. If this is not the case, see the article How to Build a Java Portlet.

- You've seen sample web services portlets provided as part of PDK-Java, and have followed the instructions provided in Installing the Web Services Sample Portlets.

- You have a basic understanding about using web services in portlets as described in the article Understanding Web Services for Portlets.

## Building Web Service Portlets

To build a portlet using a Web Service, you need to follow the following three main steps:

1. You point the PDK-Java framework to your web service by filling in the appropriate tags in the provider.xml file. You can fill in portlet information, and the web services related details using the built-in renderers.
2. Register your Provider with Oracle9iAS Portal
3. Display the portlet on a page

For building your own Web Service, you can use Oracle9i JDeveloper which has a great feature set especially for web services. The Web Services Description Language (WSDL) is an XML vocabulary that provides a standard way of describing Web Service details like the service location, method parameters and data types With Jdeveloper, you can use features like the client stub generation wizard that takes a WSDL URL and generates the stub class automatically. This stub class provides a wrapper for communication between the Portal and the Web Service.

So you can use JDeveloper to complement the capability of invoking web services. For an RPC style web service, you need you need to to use the built-in RPCWebServiceRenderer class, and fill in relevant tags in the provider.xml.

- You can setup your Web Service to use the generated stub classes that facilitate communication between the Portal and the Web Service.
- You can also have Web Service portlets communicate with other portlets, and pass parameters to Web Service portlets with declarative parameter bindings.
- You can also control how the portlet displays the data from a Web Service by passing the data through XSL stylesheets.

For a DOC style Web Service, you need to to use the built-in DocWebServiceRenderer class.

- You can setup your Web Service to use the WSDL details like endPointURL and SOAPAction that facilitate communication automatically. You can plug-in such information from the WSDL doc of the Web Service, directly into the provider.xml.
- PDK-Java provides built-in classes to handle literal XML and you have to just point to the existing classes.
- As before, you can also have Web Service portlets communicate with other portlets, and pass parameters to Web Service portlets with declarative parameter bindings.
- You can also control how the portlet displays the data from a Web Service by passing the data through XSL stylesheets. If you do not provide a stylesheet, a default one is generated for you by PDK-Java.

## Using the Web Service Renderers

First, you need to select the web service that you plan to expose as a portlet. You may use a formal UDDI registry service, or a web site such as xmethods.net to locate a suitable web service.

Next, you need to establish the interface that the web service supports. The interface of a web service is generally described using an XML language called Web Services Description Language or WSDL. The URL to a WSDL document should be one of the attributes published for the web service you located.

Among other interface properties, a WSDL document defines the set of 'bindings' the web service supports, i.e. the different protocol formats through which it can be invoked. To be compatible with the PDK-Java web service renderers, the service must support a Simple Object Access Protocol (SOAP) binding, and hence should have a <binding> element in its WSDL document which contains a <soap:binding> element. The <soap:binding> element defines an important characteristic of the SOAP protocol binding which will determine which of the PDK-Java web service renderers you should select for rendering the web service.

- If the binding is RPC style, e.g. <soap:binding style="rpc">, then the web service communicates using a specialized syntax to encode remote procedure calls. The request to the web service enodes an argument list to a procedure to be called on the remote service, while its response encodes the procedure's return value or an exception if an error occurs. For such bindings you should use RPCWebServiceRenderer to expose the web service as a portlet.
- If the binding is document style, e.g. <soap:binding style="doc">, then the web service communicates using an unconstrained XML format. For such bindings you should use DocWebServiceRenderer to expose the web service as a portlet.

Once you have decided on which style of SOAP binding the web service supports, and hence which renderer class you should use, you need to "wire it in" to a portlet. The following subsections explain how you would do this for both RPCWebServiceRenderer and DocWebServiceRenderer.

### Invoking RPC-style Web Services

RPCWebServiceRenderer builds on the automated support for RPC style web services built in to Oracle JDeveloper version 9.0.2 and later. It assumes that you have used JDeveloper to analyze the web service's WSDL document and automatically generate a 'stub' or 'proxy' class for the web service which translates from Java method calls into remote procedure calls on the web service. Consult the JDeveloper section of otn.oracle.com to find out how to download JDeveloper, and consult the JDeveloper online help for details of how to generate web service stubs.

Once you have the Java stub for your RPC web service, you just need to tell RPCWebServiceRenderer which of the methods on the stub it should call, and what parameters to pass to the method (if any). This is done in the XML provider definition. An extract from the sample provider.xml showing the declaration for the stock quote portlet is shown below.

    <showPage class="oracle.portal.provider.v2.webservice.RPCWebServiceRenderer">
      <contentType>text/html</contentType>
      <logging>false</logging>
      <className>oracle.portal.sample.v2.devguide.webservices.NetXmethodsServicesStockquoteStockQuoteServiceStub</className>
      <renderMethod>getQuote</renderMethod>
      <param class="oracle.portal.provider.v2.webservice.WebServiceRenderer$URLParam">
        <name>symbol</name>
        <default>ORCL</default>
        <prompt>Please enter a stock symbol</prompt>
      </param>
      <responseXSL>stockQuoteResponse.xsl</responseXSL>
    </showPage>

As you can see, the Java class name of the stub is specified using the className element, and the method to call on the stub is specified using the renderMethod element.

There is also an element called responseXSL which defines the name of the XSL stylesheet used to transform the web service response into portlet markup. The stylesheet is stored in the same directory as the XML provider definition. Although this filename must be specified, the file need not exist, as the renderer will generate you a default XSL stylesheet if one is not already present. Once you have this basic stylesheet, you may later decide to 'fine tune' the porlet presentation by customizing the XSL for yourself.

Each parameter into the render method is declared in order using a param element. To declare a parameter bound to a constant value, you can use the param element in its 'simple' form, e.g.:

> <param>123</param>

Note that you don't have to specify type information for each parameter - the parameter value is automatically converted into the appropriate type according to the argument list of the method.

To declare a parameter sourced from elsewhere, you have to use the param element in 'extended' from by specifying a class attribute with one of the following values (consult the PortletRenderRequest Javadoc for more details):

- oracle.portal.provider.v2.webservice.WebServiceRenderer$RequestParam: The parameter is bound to an attribute of the portlet render request, specified by the <name> element. This can be any of the following:
  - user/name: The Portal user id of the user accessing the portlet
  - user/authLevel: An integer denoting the current level of 'trust' Portal has with this user
  - locale/language: The ISO language code for the locale the user has logged in with
  - locale/country: The ISO country code for the locale the user has logged in with (may be empty)
  - pageURL: The URL through which the Portal page has been accessed, including context parameters
  - formActionLink: The URL to which HTML forms generated by this porlet should post
  - requestPath: The URL through which the web provider was called (used to qualify image links, etc.)
  - parameterPrefix: The portlet instance-specific prefix which should be used to qualify query string parameters appended to the page URL.
- oracle.portal.provider.v2.webservice.WebServiceRenderer$URLParam: The parameter is bound to a parameter in the query string of the Portal page URL with a name specified by the <name> element. Note that this may be a portlet 'private' parameter whose name is prefixed with parameterPrefix, or may be a 'public' unqualified parameter with the given name.
- oracle.portal.provider.v2.webservice.WebServiceRenderer$SessionAttrib: The parameter is bound to the attribute of the ProviderSession with name specified by the <name> element.
- oracle.portal.provider.v2.webservice.WebServiceRenderer$EditData: The parameter is bound to the string value stored against the name specified by the <name> element in the NameValuePersonalizationObject containing the customization data for the current user and portlet instance. Note that non-string typed values and other customization data classes are not currently supported.

For each of the above parameter binding types, you can also specify extra properties in child elements of the param element, allowing extra control over the parameter binding:

- default: A default value for the parameter to use if its binding is null or the empty string
- mandatory: If set to true, the web service will not be called if the binding is null or the empty string. This is useful when the argument list to the web service is built up in a multi-stage form.

For URL parameters, you can also use a special property called prompt to define the prompt to use for a field which accepts the value of the parameter in an HTML form. This property is used to drive the generation of the default XSL stylesheet which presents the web service output.

### Invoking Document-style Web Services

Because the structure of the XML sent to a doc style web service is far less constrained than that sent to an RPC style seb service, it is not so easy to generate a 'stub' class for a doc style web service that packages up all the 'arguments' into the web service into the appropriate XML structure. For this reason, DocWebServiceRenderer takes over the role of the stub as well as the portlet renderer, and uses a powerful extension to the provider.xml syntax to define argument bindings into an arbitrary XML structure.

As an example, an extract from the sample provider.xml showing the declaration for the "Who Is" portlet is included below.

    <showPage class="oracle.portal.provider.v2.webservice.DocWebServiceRenderer">
      <contentType>text/html</contentType>
      <logging>false</logging>
      <endpointURL>http://www.esynaps.com/WebServices/WhoIsService.asmx</endpointURL>
      <soapAction>http://tempuri.org/WhoIs</soapAction>
      <literal class="oracle.portal.provider.v2.webservice.LiteralXML"
        handler="oracle.portal.provider.v2.webservice.LiteralXML$Handler">
        <element name="WhoIs">
        <attribute name="xmlns">http://tempuri.org/</attribute>
        <element name="DomainName"
          bind="urlParams/domainName"
          default="oracle.com"
          prompt="Please enter an Internet Domain name"/>
        </element>
      </literal>
      <!-- This service produces HTML as output, so don't escape tag information -->
      <escapeOutput>false</escapeOutput>
      <responseXSL>whoIsResponse.xsl</responseXSL>
    </showPage>

This time, the endpointURL element defines the URL through which the web service is contacted and the soapAction element defines the value to be set for the SOAPAction HTTP header, if required. These attributes can easily be obtained from inspection of the WSDL document of the web service. The endpoint URL is specified within the <soap:address> element, while the SOAP Action should be specified in the soapAction attribute of the <soap:operation> element corresponding to the particular operation you want to invoke.

As well as specifying the parameter bindings into a doc style web service you must also specify the XML structure into which the values should be inserted. This is done using the literal element of the provider definition. A literal declaration should always begin as follows:

>     <literal class="oracle.portal.provider.v2.webservice.LiteralXML"
>       handler="oracle.portal.provider.v2.webservice.LiteralXML$Handler">

This tells the provider definition processing code to hand over control to the special 'node handler' called LiteralXML$Handler, which is capable of processing the structured XML descriptions. Inside the literal element, you can use a combination of nested <element> and <attribute> elements to convey the structure of the XML and its bindings.

The <attribute> element describes an XML attribute whose name is specified by its name attribute. An <attribute> element can optionally contain text, corresponding to a constant value for the attribute.

Similarly, the <element> element describes an XML element whose name is specified by its name attribute. An <element> can optionally contain text, corresponding to constant textual content of the element, <attribute> elements, corresponding to attributes set on the element and further child <elements> corresponding to nested elements.

Both <element>s and <attribute>s can be 'bound' to dynamic content described by a bind attribute. A bind attribute should consist of a type name and a parameter name separated by a '/' character. As per RPCWebServiceRenderer, the bind type name controls where the bound value is sourced from and the same set of sources are supported. The allowed bind type names and their meanings are listed below:

- request: The element or attribute is bound to an attribute of the portlet render request, specified by the suffix of the bind attribute. This can be any of the attributes listed for oracle.portal.provider.v2.webservice.WebServiceRenderer$RequestParam above.
- urlParams: The element or attribute is bound to a parameter in the query string of the Portal page URL with a name specified by the suffix of the bind attribute.
- session: The element or attribute is bound to the attribute of the ProviderSession with name specified by the suffix of the bind attribute.
- editData: The element or attribute is bound to the string value stored in a NameValuePersonalizationObject against the name specified by the suffix of the bind attribute.

Both <element> and <attribute> also support prompt and mandatory attributes, which have the same meaning as per RPCWebServiceRenderer.

This may all sound rather complicated, but you should find that the syntax is fairly intuitive. For example, the literal element above describes an XML structure that looks like the following:

        <WhoIs xmlns="http://tempuri.org/">
          <DomainName>oracle.com</DomainName>
        </WhoIs>

## Customizing Presentation using Stylesheets

As mentioned earlier, knowledge of XSL and XSLT is not required in order to get basic results from the renderers. However, by writing custom XSL, a user can gain more control over the markup generated by the renderer, and can present structured information more effectively, e.g. in an HTML table.

To be able to write appropriate XSL to present your web service results, you need some knowledge of the structure of the XML document which is passed through the XSLT transformation. An example listing is included below.

    <doc>
       <request>
          <user>
             <name>PORTAL30</name>
             <authLevel>10</authLevel>
          </user>
          <formActionLink>http://my.host.com:7778/servlet/page</formActionLink>
          <parameterPrefix>703031269.2.1704_STOCKQUOTE_703031269.</parameterPrefix>
          <locale>
             <country></country>
             <language>en</language>
          </locale>
          <requestPath>http://my.host.com:7778/jpdk/</requestPath>
          <pageURL>http://my.host.com:7778/servlet/page?_pageid=785&amp;_dad=p30980&amp;_schema=PORTAL30</pageURL>
       </request>
       <pageParams>
          <param>
             <name>_pageid</name>
             <value>785</value>
          </param>
          <param>
             <name>_dad</name>
             <value>p30980</value>
          </param>
          <param>
             <name>_schema</name>
             <value>PORTAL30</value>
          </param>
       </pageParams>
       <urlParams>
          <param>
             <name>_portal_id</name>
             <value>70303</value>
          </param>
          <param>
             <name>_user</name>
             <value>PORTAL30</value>
          </param>
          <param>
             <name>_render_mode</name>
             <value>1</value>
          </param>
          <param>
             <name>_provider_id</name>
             <value>703031269</value>
          </param>
          <param>
             <name>_auth_level</name>
             <value>10</value>
          </param>
          <param>
             <name>_portlet_id</name>
             <value>2</value>
          </param>
          <param>
             <name>_instance_name</name>
             <value>1704_STOCKQUOTE_703031269</value>
          </param>
          <param>
             <name>_design_url</name>
             <value>http://my.host.com:7778/servlet/page?_dad=p30980&amp;_schema=PORTAL30&amp;_type=portlet&amp;_providerid=703031269&amp;_portletid=2&amp;_referencepath=1704_STOCKQUOTE_703031269&amp;_backurl=http%3A%2F%2Fwebdbsvr2.us.oracle.com%3A30980%2Fservlet%2Fpage%3F_pageid%3D785%26_dad%3Dp30980%26_schema%3DPORTAL30</value>
          </param>
          <param>
             <name>_back_url</name>
             <value>null</value>
          </param>
          <param>
             <name>_login_url</name>
             <value>http://my.host.com:7778/pls/p30980_sso/portal30_sso.wwsso_app_admin.fapp_process_login?p_app_id=</value>
          </param>
          <param>
             <name>_page_url</name>
             <value>http://my.host.com:7778/servlet/page?_pageid=785&amp;_dad=p30980&amp;_schema=PORTAL30</value>
          </param>
          <param>
             <name>_border</name>
             <value>1</value>
          </param>
          <param>
             <name>_action</name>
             <value>showPortlet</value>
          </param>
          <param>
             <name>_has_title</name>
             <value>1</value>
          </param>
       </urlParams>
       <session>
         <attribute>
           <name>some_attribute</name>
           <value>some_value</value>
         </attribute>
       </session>
       <editData>
         <attribute>
           <name>some_item</name>
           <value>some_value</value>
         </attribute>
       </editData>
       <bindings>
          <param>
             <name>symbol</name>
             <value>ORCL</value>
          </param>
       </bindings>
       <response>
         <return>48.5</return>
       </response>
    </doc>

As you can see, below the main document element, doc, there are seven main elements. The function of each of these elements is explained below:

1. request: a description of the Portlet Render Request. The list of properties included is exactly the same as for those supported by WebServiceRenderer$RequestParam above. Where an property name has a 'path', such as "user/name", its element is nested inside grouping elements corresponding to the path.
2. pageParams: a list of the "context parameters" in the page URL and their values. When posting data back to a portlet with an HTML form, you must include all these parameters in hidden fields in the form.
3. urlParams: a list of all the parameters in the query string of the Portal page URL, including portlet-specific 'private' parameters, as per WebServiceRenderer$UrlParam. Note that the portlet-specific prefix is stripped from private parameter names.
4. session: a list of the attributes in the ProviderSession (if there is one) and their values, as per WebServiceRenderer$UrlParam.
5. editData: a list of portlet customization name value pairs, as stored in the NameValuePersonalizationObject for the current portlet instance, if one exists, as per WebServiceRenderer$EditData.
6. bindings: a list of the names and values of the parameters sent into the web service. This is useful, e.g. when setting defaults for fields in generated HTML forms.
7. response: the value returned by the web service. If the web service returns literal XML, this will be a nested XML structure.

To get an idea of how you might transform such a document into a portlet, have a look at the XSL files for the sample portlets in j2ee/home/applications/jpdk/jpdk/WEB-INF/providers/webservices.

## Debugging Features

Not everyone gets their XSL and parameter bindings correct first time, so to help debugging, the WebServiceRenderers have the following features:

- Auto reload of XSL documents: If the renderer detects that an XSL document has been edited since it was last parsed, it is reparsed.
- XML logging: To help track down where things are going wrong, the renderers support a boolean <logging> element in their XML definition. When true, the renderers dump XML documents corresponding to various stages in the renderering process. These documents are dumped to the same directory in which the stylesheets and XML provider definition are stored. The document filenames are prefixed with the unique portlet instance name, and have one of the following suffixes:
  - _literal.xml: A dump of the instantiated literal XML structure, which was sent to the web service. This is only written when the web service arguments are defined with a <literal> element.
  - _request.xml: A snapshot of the combined response document before the web service was invoked. This helps when validating that all the correct arguments are being passed.
  - _request.xml: A snapshot of the combined response document after the web service has been invoked and its response has been added. This is the XML document to which the stylesheet is applied. If this document is missing, it probably means that an exception occurred when calling the web service. You should check j2ee/home/application-deployments/jpdk/application.log to find a log of all the exceptions that occurred.

For answers to frequently asked questions and background information read the Web Services FAQ.

## Summary

Ultimately, your choice of the type of information storage depends on the nuances of your specific application. Oracle9iAS Portal provides support for all these different types of storages so you can build an optimum solution.

Revision History: |
Revision No | Last Update
1.0 1.1 | April 4, 2002 July 28, 2002

Oracle Corporation World Headquarters 500 Oracle Parkway Redwood Shores, CA 94065, USA http://www.oracle.com/ | Worldwide Inquiries: 1-800-ORACLE1 Fax 650.506.7200 | Copyright and Corporate Info