Tutorial 36: How to use a Web Service in a Formspider Application

This tutorial describes how to use a web service in a Formspider application. It shows how to build an application displaying current weather report for the selected state invoking an external web service from U.S. National Weather Service (NWS).

You may click here to run the application.

Sample Web Service Definition

NWS provides a web service containing various functions allowing public, government agencies and commercial enterprises to access data from the National Digital Forecast Database (NDFD). See the link below for the detailed information and the complete list of functions provided by NWS web service;
http://graphical.weather.gov/xml/

Also, you can access to the web service description from the link below;
http://graphical.weather.gov/xml/DWMLgen/wsdl/ndfdXML.wsdl

This tutorial uses NDFDgenByDay() function defined as a part of NWS web service. This function returns NDFD data for a specified point (identified by its latitude and its longitude), starting from a specified date. A sample SOAP request for the NDFDgenByDay() interface is as the following:

<soapenv:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ndf="http://graphical.weather.gov/xml/DWMLgen/wsdl/ndfdXML.wsdl">
   <soapenv:Header/>
   <soapenv:Body>
      <ndf:NDFDgenByDay soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
         <latitude xsi:type="xsd:decimal">27.766279</latitude>
         <longitude xsi:type="xsd:decimal">-81.686782</longitude>
         <startDate xsi:type="xsd:date">2012-05-11</startDate>
         <numDays xsi:type="xsd:integer">1</numDays>
         <Unit xsi:type="dwml:unitType" xmlns:dwml="http://graphical.weather.gov/xml/DWMLgen/schema/DWML.xsd">m</Unit>
         <format xsi:type="dwml:formatType" xmlns:dwml="http://graphical.weather.gov/xml/DWMLgen/schema/DWML.xsd">24 hourly</format>
      </ndf:NDFDgenByDay>
   </soapenv:Body>
</soapenv:Envelope>

The SOAP response returned for the sample request above is:

<SOAP-ENV:Envelope SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/">
   <SOAP-ENV:Body>
      <ns1:NDFDgenByDayResponse xmlns:ns1="http://graphical.weather.gov/xml/DWMLgen/wsdl/ndfdXML.wsdl">
         <dwmlByDayOut xsi:type="xsd:string"><![CDATA[<?xml version="1.0"?>
<dwml version="1.0" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://graphical.weather.gov/xml/DWMLgen/schema/DWML.xsd">
  <head>
    <product srsName="WGS 1984" concise-name="dwmlByDay" operational-mode="official">
      <title>NOAA's National Weather Service Forecast by 24 Hour Period</title>
      <field>meteorological</field>
      <category>forecast</category>
      <creation-date refresh-frequency="PT1H">2012-05-11T11:39:49Z</creation-date>
    </product>
    <source>
      <more-information>http://graphical.weather.gov/xml/</more-information>
      <production-center>Meteorological Development Laboratory<sub-center>Product Generation Branch</sub-center></production-center>
      <disclaimer>http://www.nws.noaa.gov/disclaimer.html</disclaimer>
      <credit>http://www.weather.gov/</credit>
      <credit-logo>http://www.weather.gov/images/xml_logo.gif</credit-logo>
      <feedback>http://www.weather.gov/feedback.php</feedback>
    </source>
  </head>
  <data>
    <location>
      <location-key>point1</location-key>
      <point latitude="27.77" longitude="-81.69"/>
    </location>
    <moreWeatherInformation applicable-location="point1">http://forecast.weather.gov/MapClick.php?textField1=27.77&amp;textField2=-81.69</moreWeatherInformation>
    <time-layout time-coordinate="local" summarization="24hourly">
      <layout-key>k-p24h-n1-1</layout-key>
      <start-valid-time>2012-05-11T06:00:00-04:00</start-valid-time>
      <end-valid-time>2012-05-12T06:00:00-04:00</end-valid-time>
    </time-layout>
    <time-layout time-coordinate="local" summarization="12hourly">
      <layout-key>k-p12h-n2-2</layout-key>
      <start-valid-time>2012-05-11T06:00:00-04:00</start-valid-time>
      <end-valid-time>2012-05-11T18:00:00-04:00</end-valid-time>
      <start-valid-time>2012-05-11T18:00:00-04:00</start-valid-time>
      <end-valid-time>2012-05-12T06:00:00-04:00</end-valid-time>
    </time-layout>
    <time-layout time-coordinate="local" summarization="24hourly">
      <layout-key>k-p1d-n1-3</layout-key>
      <start-valid-time>2012-05-11T06:00:00-04:00</start-valid-time>
      <end-valid-time>2012-05-12T06:00:00-04:00</end-valid-time>
    </time-layout>
    <parameters applicable-location="point1">
      <temperature type="maximum" units="Celsius" time-layout="k-p24h-n1-1">
        <name>Daily Maximum Temperature</name>
        <value>32</value>
      </temperature>
      <temperature type="minimum" units="Celsius" time-layout="k-p24h-n1-1">
        <name>Daily Minimum Temperature</name>
        <value>18</value>
      </temperature>
      <probability-of-precipitation type="12 hour" units="percent" time-layout="k-p12h-n2-2">
        <name>12 Hourly Probability of Precipitation</name>
        <value>10</value>
        <value>5</value>
      </probability-of-precipitation>
      <weather time-layout="k-p24h-n1-1">
        <name>Weather Type, Coverage, and Intensity</name>
        <weather-conditions weather-summary="Partly Sunny"/>
      </weather>
      <conditions-icon type="forecast-NWS" time-layout="k-p24h-n1-1">
        <name>Conditions Icons</name>
        <icon-link>http://www.nws.noaa.gov/weather/images/fcicons/sct.jpg</icon-link>
      </conditions-icon>
      <hazards time-layout="k-p1d-n1-3">
        <name>Watches, Warnings, and Advisories</name>
        <hazard-conditions xsi:nil="true"/>
      </hazards>
    </parameters>
  </data>
</dwml>]]></dwmlByDayOut>
      </ns1:NDFDgenByDayResponse>
   </SOAP-ENV:Body>
</SOAP-ENV:Envelope>

Consuming the Web Service

In your datasource schema, create a package called “webservice_pkg” and open your newly created “webservice_pkg” package in your favorite PL/SQL Editor. Add a function named “genCurrentWeatherReportXML” and ensure that it’s exposed in the package specification. This function creates a SOAP request for the given latitude-longitude pair and invoke the NDFDgenByDay function. It uses utl_http package to consume the web service and returns the complete NDFD data (SOAP response body) in XMLType format.

function genCurrentWeatherReportXML(in_latitude_nr number, in_longitude_nr number) return xmltype
as
  v_soapRequest_tx        varchar2(32767);
  v_soapResponseChunk_tx  varchar2(32767);
  v_NDFDData_xml          XMLType;
  v_httpResponse          utl_http.resp;
  v_httpRequest           utl_http.req;
  v_soapResponse_cl       clob;
  v_bufferSize_nr         number                 := 32766;
  v_endPointURL_tx        constant varchar2(255) := 'http://graphical.weather.gov/xml/SOAP_server/ndfdXMLserver.php';
  -- fixed web service parameters
  v_startDate_tx          constant varchar2(255) := ''; -- earliest date available in NDFD
  v_numDays_nr            constant number        := 1;
  v_unit_tx               constant varchar2(1)   := 'm';
  v_format_tx             constant varchar2(255) := '24 hourly';
begin

  if in_latitude_nr is not null and in_longitude_nr is not null then

    dbms_lob.createtemporary(v_soapResponse_cl, false);

    -- create SOAP request
    v_soapRequest_tx :=
    '<soapenv:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ndf="http://graphical.weather.gov/xml/DWMLgen/wsdl/ndfdXML.wsdl">' ||
      '<soapenv:Header/>' ||
      '<soapenv:Body>' ||
          '<ndf:NDFDgenByDay soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">' ||
              '<latitude xsi:type="xsd:decimal">' || in_latitude_nr ||'</latitude>' ||
              '<longitude xsi:type="xsd:decimal">' || in_longitude_nr ||'</longitude>' ||
              '<startDate xsi:type="xsd:date">' || v_startDate_tx || '</startDate>' ||
              '<numDays xsi:type="xsd:integer">' || v_numDays_nr || '</numDays>' ||
              '<Unit xsi:type="dwml:unitType" xmlns:dwml="http://graphical.weather.gov/xml/DWMLgen/schema/DWML.xsd">' || v_unit_tx || '</Unit>' ||
              '<format xsi:type="dwml:formatType" xmlns:dwml="http://graphical.weather.gov/xml/DWMLgen/schema/DWML.xsd">' || v_format_tx || '</format>' ||
          '</ndf:NDFDgenByDay>' ||
      '</soapenv:Body>' ||
    '</soapenv:Envelope>';

    -- invoke web service
    v_httpRequest:= utl_http.begin_request(v_endPointURL_tx, 'POST', 'HTTP/1.1');
    utl_http.set_header(v_httpRequest, 'Content-Type', 'text/xml');
    utl_http.set_header(v_httpRequest, 'Content-Length', length(v_soapRequest_tx));
    utl_http.set_header(v_httpRequest, 'SOAPAction', '');
    utl_http.write_text(v_httpRequest, v_soapRequest_tx);
    v_httpResponse:= utl_http.get_response(v_httpRequest);

    -- read web service response into clob
    begin
      loop
        utl_http.read_text(v_httpResponse, v_soapResponseChunk_tx, v_bufferSize_nr);
        dbms_lob.writeappend(v_soapResponse_cl, length(v_soapResponseChunk_tx), v_soapResponseChunk_tx);
      end loop;
    exception
      when utl_http.end_of_body then
        utl_http.end_response(v_httpResponse);
    end;

    -- extract CDATA section from the web service response xml
    v_soapResponse_cl := XMLType.createXML(v_soapResponse_cl).extract('//text()').getClobVal();
    -- decode extracted response XML and create an XMLType variable containing this  XML
    v_NDFDData_xml := XMLType.createXML(dbms_xmlgen.convert(v_soapResponse_cl, dbms_xmlgen.ENTITY_DECODE));
  end if;

  return v_NDFDData_xml;
end;

Note that while creating the SOAP request envelope, the function uses null as the “startDate” parameter value to get the earliest date available in NDFD and 1 as “numDays” parameter. It means that only current date’s data is requested.

You can further examine the NDFD data XML returned by this function for Florida using the following query:

select webservice_pkg.genCurrentWeatherReportXML(27.766279, -81.686782) from dual

Creating the Formspider application

Open Formspider IDE and click “New Application” under the “File” menu, the “New Application” dialog shows up. Enter “webService” as the name of the application and the name of the schema where you have created “webservice_pkg” package as datasource schema name.  If you are using Formspider Online, you do not need to enter database schema name since your account is already configured to use your online database. Leave other fields empty and click “OK”. This creates the “webService” application with a default mainframe (called “mainFrame”) and a default panel (called “mainPanel”).

The sample application contains a combobox listing state names, three labels and an image component displaying weather information of the selected state through the combobox.

Create a new datasource definition. To achieve this, expand the “Datasource Definitions” accordion, select the “Datasource Definitions” node and click the “+” button. Alternatively, you may right click the “Datasource Definitions” node and select “New” from the pop up menu. The “New Datasource Definition” dialog shows up. Select the “Query” radio button from the “Based On” section and enter “weatherReport” as “Name” of the datasource definition.

Creating “weatherReport” datasource definition

This datasource definition holds current weather information for a given point. To populate this information, it queries the SOAP response XML provided by “webservice_pkg.genCurrentWeatherReportXML” function and retrieves necessary information from this XML.

Select “Query” node in the navigation tree on the left. Enter the following SQL Statement:

select maxTempDesc || ': ' || maxTempValue || ' ' || maxTempUnit as maxTempInfo
      ,minTempDesc || ': ' || minTempValue || ' ' || minTempUnit as minTempInfo
      ,weatherIcon
      ,weatherDesc
from(
      select maxTempDesc
            ,maxTempValue
            ,maxTempUnit
            ,minTempDesc
            ,minTempValue
            ,minTempUnit
            ,weatherIcon
            ,weatherDesc
       from xmltable('/dwml/data/parameters'
                      passing webservice_pkg.genCurrentWeatherReportXML(:latitude_nr, :longitude_nr)
                      columns
                      maxTempDesc varchar2(4000) path 'temperature[@type="maximum"]/name'
                     ,maxTempValue number        path 'temperature[@type="maximum"]/value'
                     ,maxTempUnit varchar2(255)  path 'temperature[@type="maximum"]/@units'
                     ,minTempDesc varchar2(4000) path 'temperature[@type="minimum"]/name'
                     ,minTempValue number        path 'temperature[@type="minimum"]/value'
                     ,minTempUnit varchar2(255)  path 'temperature[@type="minimum"]/@units'
                     ,weatherIcon varchar2(4000) path 'conditions-icon/icon-link'
                     ,weatherDesc varchar2(4000) path 'weather/weather-conditions/@weather-summary'
                    )
    )

Entering Query for “weatherReport” datasource definition

Note that this query contains two bind variables named “latitude_nr” and “longitude_nr”. Click the “Bind Variables” node to register “latitude_nr” and “longitude_nr” bind variables. Click “New BindVar” button, a new row appears in the grid. Enter “latitude_nr” to the “Name” column and select “DefaultNumber″ as the “Domain” value. Click “New BindVar” button again, this time enter “longitude_nr” as “Name” and select “DefaultNumber″ as the “Domain” value.

Creating “latitude_nr” and “longitude_nr” bind variables

Click “OK” to save and close the “New Datasource Definition” dialog. This creates the “weatherReport” datasource definition and the “weatherReport1″ datasource.

Create a new datasource definition holding names, latitude and longitude infornation of major states. To achieve this, select “Datasource Definitions” node and click the “+” button again. Select the “Query” radio button, enter “states” as “Name” of the datasource definition.

Select “Query” node in the navigation tree on the left. Enter the following SQL Statement:

select 'Arizona' as stateName, 33.729761 as latitude, -111.431224 as longitude from dual
union all
select 'California', 36.116203, -119.681563 from dual
union all
select 'Florida', 27.766279, -81.686782 from dual
union all
select 'Illinois', 40.349455, -88.986137 from dual
union all
select 'Indiana', 39.849425, -86.258278 from dual
union all
select 'Michigan', 43.326618, -84.536093 from dual
union all
select 'New York', 42.165724, -74.948052 from dual
union all
select 'Pennsylvania', 40.590752, -77.209755 from dual
union all
select 'Texas', 31.054487, -97.56346 from dual
union all
select 'Washington', 47.400902, -121.490493 from dual

Select “Datasource Definition” node in the navigation tree on the left and select “STATENAME” from the “Primary Key” combobox.

Defining primary key for “states” datasource definition

Click “OK” to save and close the “New Datasource Definition” dialog. This creates the “states” datasource definition and the “states1″ datasource.

Expand the “Panels” node from the “Containers” tree and double click the “mainPanel” to open it in the editor. Add a combobox listing states using the “states1” datasource, three labels and an image component displaying current weather information for the selected state using “weatherReport1” datasource. The “mainPanel” XML should look like the following;

<panel>
  <tableLayout>
    <row/>
    <row height="55">
      <cell width="110" hAlign="Full" vAlign="Center">
        <textLabel label="Please select a state:" text-align="Left"/>
      </cell>
      <cell width="150" hAlign="Center" vAlign="Center" childWidth="130">
        <comboBox name="cb_state" displayColumn="STATENAME" valueColumn="STATENAME" displayNullOption="Y" listDataSource="states1"/>
      </cell>
      <cell hAlign="Center" vAlign="Full" childWidth="58">
        <image name="image_weatherCondition"/>
      </cell>
    </row>
    <row height="20">
      <cell columnSpan="2"/>
      <cell hAlign="Full" vAlign="Full">
        <textLabel font-style="Bold" text-align="Center" column="WEATHERDESC" dataSource="weatherReport1"/>
      </cell>
    </row>
    <row height="20">
      <cell columnSpan="2"/>
      <cell hAlign="Full" vAlign="Full">
        <textLabel text-align="Center" column="MAXTEMPINFO" dataSource="weatherReport1"/>
      </cell>
    </row>
    <row height="20">
      <cell columnSpan="2"/>
      <cell hAlign="Full" vAlign="Full">
        <textLabel text-align="Center" column="MINTEMPINFO" dataSource="weatherReport1"/>
      </cell>
    </row>
    <row/>
  </tableLayout>
</panel>

When a state is selected from the combobox, the weather information corresponding to the selected state should be generated. Therefore the “weatherReport1” datasource should be executed with the corresponding latitude and longitude values each time a state is selected. To achieve this you have to create an action which fires when a state is selected from the combobox.

Open “webservice_pkg” package and create a procedure named “selectState”, this procedure uses api_datasource.getcolumnvaluenrbypk API to obtain latitude and longitude values belonging to the selected state from “states1” datasource. It populates corresponding weather data by executing “weatherReport1” datasource with the obtained latitude-longitude pair and sets the image component’s url to display graphical representation of the weather condition.

procedure selectState is
  v_selectedState_tx  varchar2(255);
  v_latitude_nr       number;
  v_longitude_nr      number;
begin

  v_selectedState_tx := api_component.getvaluetx('mainPanel.cb_state');
  if v_selectedState_tx is not null then
    v_latitude_nr := api_datasource.getcolumnvaluenrbypk('states1.latitude', v_selectedState_tx);
    v_longitude_nr := api_datasource.getcolumnvaluenrbypk('states1.longitude', v_selectedState_tx);
  end if;

  api_datasource.setbindvar('weatherReport1.latitude_nr', v_latitude_nr);
  api_datasource.setbindvar('weatherReport1.longitude_nr',v_longitude_nr);
  api_datasource.executequery('weatherReport1');

  if api_datasource.getcurrentrowid('weatherReport1') is not null then
    api_component.seturl('mainPanel.image_weatherCondition', api_datasource.getcolumnvaluetx('weatherReport1.weathericon'));
  else
    api_component.seturl('mainPanel.image_weatherCondition', ' ');
  end if;

end;

In Formspider IDE expand the “Actions” accordion, select the “Actions” node, click the “+” button to create a new action. Alternatively you may right click the “Actions” node and select “New” from the pop-up menu. The “New Action” dialog shows up. Enter “selectState” as the action name and “webservice_pkg.selectState” as the procedure. Click “OK” to save your action.

Creating “selectState” action

Open “mainPanel”, add a “valueChanged” event triggering “selectState” action to the combobox listing states:

<panel>
  <tableLayout>
    <row/>
    <row height="55">
      <cell width="110" hAlign="Full" vAlign="Center">
        <textLabel label="Please select a state:" text-align="Left"/>
      </cell>
      <cell width="150" hAlign="Center" vAlign="Center" childWidth="130">
        <comboBox name="cb_state" displayColumn="STATENAME" valueColumn="STATENAME" displayNullOption="Y" listDataSource="states1">
          <events>
            <valueChanged action="selectState"/>
          </events>
        </comboBox>
      </cell>
      <cell hAlign="Center" vAlign="Full" childWidth="58">
        <image name="image_weatherCondition"/>
      </cell>
    </row>
    <row height="20">
      <cell columnSpan="2"/>
      <cell hAlign="Full" vAlign="Full">
        <textLabel font-style="Bold" text-align="Center" column="WEATHERDESC" dataSource="weatherReport1"/>
      </cell>
    </row>
    <row height="20">
      <cell columnSpan="2"/>
      <cell hAlign="Full" vAlign="Full">
        <textLabel text-align="Center" column="MAXTEMPINFO" dataSource="weatherReport1"/>
      </cell>
    </row>
    <row height="20">
      <cell columnSpan="2"/>
      <cell hAlign="Full" vAlign="Full">
        <textLabel text-align="Center" column="MINTEMPINFO" dataSource="weatherReport1"/>
      </cell>
    </row>
    <row/>
  </tableLayout>
</panel>

Press “Run on Web” button to run your application. Select a state from the combobox, the corresponding weather information is displayed. You may click here to run the application.

Web service successfully used in the Formspider application