Professional Documents
Culture Documents
09 Jan 2003 Developing applications that access both Web services and database management systems can be an overwhelming task. It doesn't need to be. This tutorial demonstrates how to generate DB2 user-defined functions (UDFs) that provide access to Web services. The generated UDFs can be used in SQL statements to combine relational data with dynamic data retrieved from a Web service. Several different examples are provided.
developerWorks
ibm.com/developerWorks
scalar functions. Web service consumer User Defined Functions (UDFs) can enable databases to directly invoke Web services using SQL. By using SQL to access Web Services data, you save effort because you can manipulate the data within the context of an SQL statement. You might think using these Web service consumer UDFs in SQL statements could be time consuming or require advanced programming skills. This tutorial will show you otherwise. It will guide you through the steps to: Enable your database for Web Service consumer UDFs Create Web service consumer UDFs using WebSphere Studio Application Developer wizard Create Web service consumer UDFs using the DB2 command line After generating and deploying the UDFs, they can be used by application programs to combine relational data with dynamic data retrieved from the Web service. Examples are given to show how to use the UDFs in SQL statements. This tutorial assumes basic knowledge of Web services, DB2 SQL, and WebSphere Studio Application Developer V5.1.1. If you are not familiar with Web services, or you could use a refresher, developerWorkshas an excellent introductory tutorial on Web services (see Resources ).
Prerequisites
To complete the steps in this tutorial, you'll need the following software installed and running: DB2 Universal Database V8.1 FixPack 4 WebSphere Studio Application Developer V5.1.1. This is optional - you can use the DB2 command line but Application Developer makes it much easier. A free trial version DB2 Universal Database V8.1 is available from the developerWorks download page. This tutorial has been revised from one originally created by Marcus Schneider and Dan Wolfson (IBM Distinguished Engineer).
Invoking Web services from SQL Copyright IBM Corporation 2003. All rights reserved.
Trademarks Page 2 of 32
ibm.com/developerWorks
developerWorks
IBM, DB2, DB2 Universal Database, DB2 Information Integrator, WebSphere and WebSphere MQ are trademarks or registered trademarks of IBM Corporation in the United States, other countries, or both. Other company, product, and service names may be trademarks or service marks of others.
Issuing these commands against the sample database results in the following output:
DXXA002I Connecting to database "SAMPLE". DXXA005I Enabling database "SAMPLE". Please wait. DXXA006I The database "SAMPLE" was enabled successfully.
Five system user-defined functions to handle SOAP are provided. These must be registered by issuing the following command:
Invoking Web services from SQL Copyright IBM Corporation 2003. All rights reserved.
Trademarks Page 3 of 32
developerWorks
ibm.com/developerWorks
db2enable_soap_udf -n database_name -u username -p password [-force] The -forceattempts to drop any existing functions. To disable the SOAP UDFs, use the following command: db2disable_soap_udf -n database_name -u username -p password The enable command copies the shared library containing the implementation of the soap functions to your sqllib/function directory. To check that you enabled the database correctly, verify the following UDFs are defined. From within the Control Center, go to Application Objects =>User Defined Functions. This should list the following:
Name SOAPHTTPV SOAPHTTPV SOAPHTTPC SOAPHTTPC SOAPHTTPCL Schema DB2XML DB2XML DB2XML DB2XML DB2XML Specific Name SOAPHTTPVIVO SOAPHTTPCIVO SOAPHTTPCICO SOAPHTTPVICO Result VARCHAR VARCHAR CLOB CLOB Input Parameters
(VARCHAR(),VARCHAR(),VARCHA
SOAPHTTPVICLO CLOB
(VARCHAR(),VARCHAR(),VARCHA
Also check to ensure db2soapudf.dll appears in your sqllib/function directory. Note:With Windows XP it may be necessary to drop the -u and -p options from the commands. HTTP proxies are not currently supported for Web Service Consumer User Defined Functions. That can cause problems when invoking the Web service.
Invoking Web services from SQL Copyright IBM Corporation 2003. All rights reserved.
Trademarks Page 4 of 32
ibm.com/developerWorks
developerWorks
1. 2. 3.
Click File =>New =>Project... from the menu bar. Use the Simple Project Template. Create a connection to the database that you just enabled. From the DB Servers view, right-click the view and select New Connection... To import the database to the project, right-click the connection and select Import to Folder... and import into your project.
You are now ready to generate your first Web service UDF. To start the wizard that generates the UDFs: 1. 2. Select File =>New =>Other. Select Dataand Web Service User-Defined Function as shown below.
Invoking Web services from SQL Copyright IBM Corporation 2003. All rights reserved.
Trademarks Page 5 of 32
developerWorks
ibm.com/developerWorks
3.
Select a WSDL
On the first page of the wizard, specify the WSDL file that will be used to generate the UDF. This can be done by using the Browse... button to select a WSDL file from the workspace or by specifying a URL. For this scenario, use a currency exchange rate Web service that takes two countries as input parameters and returns the currency exchange rate between them. Copy the following URL and paste it into the text field: http://www.xmethods.net/sd/2001/CurrencyExchangeService.wsdl
Invoking Web services from SQL Copyright IBM Corporation 2003. All rights reserved.
Trademarks Page 6 of 32
ibm.com/developerWorks
developerWorks
Click Next.
Select a database
The next page of the wizard shows the database connection and schema for which the UDF will be generated. The wizard requires that the database is enabled for the SOAP UDFs and XML Extender. This can be verified by the presence of the DB2XML schema. If no connection to the specified database is available, a pop-up window asks for connection information.
Invoking Web services from SQL Copyright IBM Corporation 2003. All rights reserved.
Trademarks Page 7 of 32
developerWorks
ibm.com/developerWorks
1. 2.
Click Browseto select a database schema from the Application Developer workspace. Choose to deploy the generated UDF into the database immediately or generate a UDF model in the Application Developer workspace only. The UDF can be deployed later by selecting the newly created UDF in the dataview, right-click it and select Build.
3.
Click Next.
Select a UDF
This page shows operations from the WSDL document. The wizard will generate one UDF for every operation that is selected. Since the Web service used for this
Invoking Web services from SQL Copyright IBM Corporation 2003. All rights reserved. Trademarks Page 8 of 32
ibm.com/developerWorks
developerWorks
example provides only one operation, this is automatically selected. Click Next.
Invoking Web services from SQL Copyright IBM Corporation 2003. All rights reserved.
Trademarks Page 9 of 32
developerWorks
ibm.com/developerWorks
function automatically maps the complex XML type into one or more columns. Switching from a table function to a scalar function makes sense when the returned types should not be automatically mapped, but returned as an XML fragment. On the other hand, switching from a scalar to a table function enables the use of the UDF in a FROM clause. It also makes it possible to include the input parameters as columns in the output table when you select the echo input parameters check box. When the service location (the locationattribute of the soap:addresselement) is not specified in the WSDL document, a dynamic function must be generated. You can select this check box even when the service location is specified to make use of late binding. When a dynamic function is generated, you need to specify the service location at run time as a parameter of the UDF. When using a Web service that can return responses of more than 3000 characters, select big SOAP response. By default, small SOAP responseis selected because it results in better performance for most Web services. If you select small SOAP responseand the Web service returns a SOAP message that is too big, the UDF will return a descriptive error message. The ability to return the whole SOAP envelope without parsing it can be useful for debugging purposes.
Invoking Web services from SQL Copyright IBM Corporation 2003. All rights reserved.
Trademarks Page 10 of 32
ibm.com/developerWorks
developerWorks
To review and/or change the mapping of WSDL types to DB2 SQL types for each parameter, click the Parameter tab
Invoking Web services from SQL Copyright IBM Corporation 2003. All rights reserved.
Trademarks Page 11 of 32
developerWorks
ibm.com/developerWorks
To specify the name for the UDF, click the Advance Options tab. If the name is not specified, then a unique name is automatically generated by the database when the UDF is deployed.
Invoking Web services from SQL Copyright IBM Corporation 2003. All rights reserved.
Trademarks Page 12 of 32
ibm.com/developerWorks
developerWorks
Invoking Web services from SQL Copyright IBM Corporation 2003. All rights reserved.
Trademarks Page 13 of 32
developerWorks
ibm.com/developerWorks
Invoking Web services from SQL Copyright IBM Corporation 2003. All rights reserved.
Trademarks Page 14 of 32
ibm.com/developerWorks
developerWorks
database. To run the deployed UDF, right-click on the UDF and select Run. The Run Settings window is displayed.
Invoking Web services from SQL Copyright IBM Corporation 2003. All rights reserved.
Trademarks Page 15 of 32
developerWorks
ibm.com/developerWorks
Invoking Web services from SQL Copyright IBM Corporation 2003. All rights reserved.
Trademarks Page 16 of 32
ibm.com/developerWorks
developerWorks
From the Run Settings window, enter the parameter values and click OK.
The result values of the UDF are shown in the Output view.
Invoking Web services from SQL Copyright IBM Corporation 2003. All rights reserved.
Trademarks Page 17 of 32
developerWorks
ibm.com/developerWorks
db2xml.soaphttpc returns CLOB(): db2xml.soaphttpc ( endpoint_url VARCHAR(256), soapaction VARCHAR(256), soap_body VARCHAR(3072) | CLOB(1M)) RETURNS CLOB(1M)
db2xml.soaphttpcl returns CLOB() as locator: db2xml.soaphttpcl( endpoint_url VARCHAR(256), soapaction VARCHAR(256), soap_body varchar(3072)) RETURNS CLOB(1M) as locator
DB2 requires the following information to build a SOAP request and receive a SOAP response: Service endpoint, e.g. http://services.xmethods.net/soap/servlet/rpcrouter SOAP action URI reference (it is optional and may be null string i.e., '' )
Invoking Web services from SQL Copyright IBM Corporation 2003. All rights reserved.
Trademarks Page 18 of 32
ibm.com/developerWorks
developerWorks
XML content of SOAP body, which are: name of operation with request namespace URI, encoding style, and input arguments
Invoking Web services from SQL Copyright IBM Corporation 2003. All rights reserved.
Trademarks Page 19 of 32
developerWorks
ibm.com/developerWorks
Test the Web service consumer functions by accessing the stock quote for IBM: 1. 2. 3. Open a DB2 command window. Connect to the database that you enabled for SOAP functions (example: SAMPLE). Create a file called getquote.sql and copy the following command into the file and save it.
<![CDATA[VALUES db2xml.soaphttpv ( ]]> 'http://66.28.98.121:9090/soap' <![CDATA[, ]]> 'urn:xmethods-delayed-quotes#getQuote' <![CDATA[, varchar ('<stock:getQuote xmlns:stock=]]> " urn:xmethods-delayed-quotes "<![CDATA[ SOAP-ENV:encodingStyle=]]> " http://schemas.xmlsoap.org/soap/encoding/ "<![CDATA[> <symbol xsi:type="xsd:string"> ]]> IBM <![CDATA[</symbol> </stock:getQuote> ' ) );]]>
Invoking Web services from SQL Copyright IBM Corporation 2003. All rights reserved.
Trademarks Page 20 of 32
ibm.com/developerWorks
developerWorks
To improve the readability of code, wrap the call to a Web service in another UDF and invoke this UDF every time you want to invoke a Web service operation. In this case, instead of calling db2xml.sopahttpv(...)every time you make a stock quote request, create a wrapper UDF that takes only the stock symbol as a parameter and internally calls the db2xml.soaphttpv(...). Define the wrapper UDF getStockQuote which takes only one parameter, namely, symbol as a VARCHAR(256) and returns Result as FLOAT. Below is the code for the getStockQuote UDF. The result of the call to db2xml.soaphttpvis a CLOB. Hence we extract the value contained in the Result element pointed to by the XPath <![CDATA['/*/Result']]> .
<![CDATA[CREATE FUNCTION ]]> SchemaName <![CDATA[.getStockQuote (symbol VARCHAR(100))RETURNS DECIMAL(5,2) SPECIFIC xmethods_getQuote LANGUAGE SQL CONTAINS SQL EXTERNAL ACTION NOT DETERMINISTIC RETURN db2xml.extractREAL( db2xml.xmlclob( db2xml.soaphttpv( ]]> 'http://66.28.98.121:9090/soap' <![CDATA[, ]]> 'urn:xmethods-delayed-quotes#getQuote' <![CDATA[, varchar('<m:getQuote xmlns:m="]]> urn:xmethods-delayed-quotes <![CDATA[" SOAP-ENV:encodingStyle="]]> http://schemas.xmlsoap.org/soap/encoding/ <![CDATA["> <symbol xsi:type="xsd:string"> ' || ]]> symbol <![CDATA[ || '</symbol></m:getQuote> ' ) ) ), '/*/Result' )]]>
Invoking Web services from SQL Copyright IBM Corporation 2003. All rights reserved.
Trademarks Page 21 of 32
developerWorks
ibm.com/developerWorks
In this wrapper UDF, only the Headline elements from the result of the Web service is extracted, a table is constructed from these elements and then the table is returned. You can invoke this UDF as follows: select * from table ( SchemaName. GetStockHeadlines('IBM', 10)) as x By issuing the above query, you should see 10 or less news headlines related to IBM stock as can be seen in the results below.
<![CDATA[STOCKNEWS --------------------------------------------------------------------IBM and ATB Financial Sign Largest IT Services Agreement of Its Kind in Western Canada [external] IBM Seen Struggling With Growth Problems
Invoking Web services from SQL Copyright IBM Corporation 2003. All rights reserved.
Trademarks Page 22 of 32
ibm.com/developerWorks
developerWorks
SCO Escalates Legal Battle on Three Fronts Hewlett-Packard Unveils High-End Copy Machines [external] Oracle Needs to See Beyond PeopleSoft [external] NEWS: Online Extra: What It "Boils Down To" For Kodak Coverage initiated on IBM by Banc of America Sec [external] ONLINE ASIA: An Irresistable Offshore Tide for Jobs [external] Hewlett-Packard Set to Make Amends Sun gives key certification to two small software cos 10 record(s) selected.]]>
Invoking Web services from SQL Copyright IBM Corporation 2003. All rights reserved.
Trademarks Page 23 of 32
developerWorks
ibm.com/developerWorks
Countries
Country us euro uk
Following is the code which creates the UDF to consume the Currency Exchange Web service.
<![CDATA[CREATE FUNCTION schemaname.getRate (country1 VARCHAR(100), country2 VARCHAR(100)) RETURNS DECIMAL(10,5) SPECIFIC xmethods_getRate LANGUAGE SQL CONTAINS SQL EXTERNAL ACTION NOT DETERMINISTIC RETURN db2xml.extractREAL( db2xml.xmlclob( db2xml.soaphttpv( 'http://66.28.98.121:9090/soap', 'urn:xmethods-CurrencyExchange#getRate', varchar( '<m:getRate xmlns:m="urn:xmethods-CurrencyExchange" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"> <country1 xsi:type="xsd:string"> ' || country1 || '</country1> <country2 xsi:type="xsd:string"> ' || country2 || '</country2> </m:getRate> ' ) ) ), '/*/Result' );]]>
Example 1
To test the function, use the following command, which will give you the exchange rate for Euro's per Dollar:
db2 values schemaname.getrate('us','euro')
The result is
0.80680
. The currency exchange rate function can be used to display price information in
Invoking Web services from SQL Copyright IBM Corporation 2003. All rights reserved. Trademarks Page 24 of 32
ibm.com/developerWorks
developerWorks
Euros instead of US dollars by accessing real-time exchange rates. Note that the built-in decimalfunction is used to cast the price information into a more readable output format.
db2 select product, decimal(schemaname.getRate('us', 'euro') * price, 10, 2) as "EUR_Price" from products
Example 2
You can also use relational data as input to the Web service. This example shows how the currency exchange rate function can be used to display price information in different currencies.
db2 SELECT p.product, c.country, decimal(schemaname.getRate('us', c.country) * price, 10, 2) as Price FROM products p, countries c
Product GEAR NUT BOLT SCREW GEAR NUT BOLT SCREW GEAR NUT BOLT SCREW
Price 950.00 50.00 100.00 40.00 766.46 40.34 80.86 32.27 511.48 26.92 53.84 21.53
developerWorks
ibm.com/developerWorks
Example 3
The statement in this example illustrates how a UDF generated as a table function can be used in a FROM clause. For this example, the getRate-UDF was regenerated as a table function and the input parameters were echoed into the output table (see Specify UDF options ).
SELECT t.* FROM countries c, table( schemaname.getRate('us', c.countries) ) t
Country1 us us us
Country2 us euro uk
Invoking Web services from SQL Copyright IBM Corporation 2003. All rights reserved.
Trademarks Page 26 of 32
ibm.com/developerWorks
developerWorks
users in the company are able to call these services from a wide variety of platforms and application environments, including a DB2 application. Each supplier offers three Web service operations that can be expressed with the following abstract signatures: getQuote (in String partNum, in Integer qty, in Date desiredDate, out Decimal price, out String currency, out Date proposedDate) purchase (in String partNum, in Integer qty, out String poNumber, out Date commitDate) getStatus (in String poNum, out String status)
Dynamic invocation
As shown in earlier sections, having a WSDL description makes it relatively easier to generate Web service UDFs for these operations. However, in this example, there are multiple service providers (suppliers) that all offer the same Web service. Here you can make use of dynamic invocation and generate one UDF for each operation that can access multiple service providers. On the Specify options page of the wizard (see Specify UDF options ), select late bindingfor the UDF. Next, you need to specify the location of the Web service as the first parameter of the UDF. From the getStatusoperation, generate a UDF with this signature:
varchar(20) GET_STATUS (url varchar(80), po_num varchar(20))
The return value is the purchase order (PO) status, and the input parameters are the URL to which the request is to be sent and the identity of the purchase order in question. Table 1 shows outstanding purchase orders, and Table 2 contains information about the Web service operations each supplier offers. Table 1: Table for purchase_orders
supplier SupplierA SupplierB SupplierC po_num 12345 22345 32345 date 3/20/02 6/20/02 5/04/02 part_num A4 C7 D7 qty 34 43 3
Invoking Web services from SQL Copyright IBM Corporation 2003. All rights reserved.
developerWorks
ibm.com/developerWorks
To find the status of a specific purchase order from a single supplier, issue the following SQL statement:
values GET_STATUS('http://www.suppliera.com/getStatus', '12345')
To find the status of all outstanding purchase orders from suppliers who offer a Web service interface, perform the operation over a set of service providers:
SELECT p.supplier, p.po_num, GET_STATUS (s.url, p.po_num) AS po_status FROM purchase_orders p, supplier_ops s WHERE p.supplier = s.supplier AND s.operation = 'getStatus'
Table functions
So far, you have been working with a function that returns a single value. The getQuote function returns multiple values. Therefore, create this function as a DB2 table function with input and output parameters as shown in Table 3. Note that the Echo input parameters check box was selected on the Specify options page (see Specify UDF options ) to include all the input values in the return table. Table 3: Parameters for the GET_QUOTE table function
Name Input url supplier part_num qty desired_date Output url supplier
Invoking Web services from SQL Copyright IBM Corporation 2003. All rights reserved.
ibm.com/developerWorks
developerWorks
This statement returns a table containing a single row with the response from SupplierA. To handle suppliers in other countries, the GET_QUOTE function contains currency units. To convert the price into dollars, use the getRate function from the currency exchange Web service:
SELECT t.supplier, t.part_num, t.qty, (t.desired_date - t.proposed_date) AS timeliness, getRate('us', t.currency)* t.price AS cost FROM TABLE(GET_QUOTE('http://www.suppliera.com/getQuote', 'SupplierA', '52435FFA', 25, '7/1/2001')) t
To reflect the difference between the desired date and the date proposed by the supplier for the part, make the columns explicit and define an output column, timeliness. Again, this query returns a single row with the quote from a single vendor for a single part. Table 4 contains a list of needed parts. Table 4: Parameters for the GET_QUOTE table function
part_num 34asfd 253kkb kj324 qty 20 34 10 desired_date 7/1/2001 8/1/2001 6/30/2001
Invoking Web services from SQL Copyright IBM Corporation 2003. All rights reserved.
Trademarks Page 29 of 32
developerWorks
ibm.com/developerWorks
This query returns a row of quotes for each part listed in the needed_parts table from SupplierA. To get quotes for each of the suppliers:
SELECT t.supplier, n.part_num, n.qty, (n.desired_date - t.proposed_date) AS timeliness, getRate('us', t.currency)* t.price AS cost FROM needed_parts n, supplier_ops s, TABLE(GET_QUOTE(s.url, s.supplier, n.part_num, n.qty, n.desired_date)) t WHERE s.operation = 'GET_QUOTE' ORDER BY cost, timeliness
This query generates quotes for all the needed parts from all the suppliers that offer the getQuote Web service and returns a table of these quotes ordered by part number and timeliness.
Section 7. Wrap up
Summary
This tutorial showed you how to generate Web service UDFs with WebSphere Studio Application Developer V5.1.1 and the DB2 command line to access Web services from database applications. Using the wizard, you can quickly generate and easily test Web service UDFs. The generated UDFs facilitate access to dynamic data sources and allow them to be easily integrated into DB2 applications.
Invoking Web services from SQL Copyright IBM Corporation 2003. All rights reserved.
Trademarks Page 30 of 32
ibm.com/developerWorks
developerWorks
Resources
Learn WebSphere Studio Application Developer developerworks Web services zone W3C Simple Object Access Protocol (SOAP) 1.2 W3C Web Services Description Language (WSDL) 1.1 "Web services - the Web's next revolution" An excellent introduction to Web services. XML Extender Administration and Programming (PDF) Stay current with developerWorks technical events and webcasts. Get products and technologies DB2 Universal Database DB2 XML Extender Build your next development project with IBM trial software, available for download directly from developerWorks. Discuss Participate in the discussion forum for this content.
Invoking Web services from SQL Copyright IBM Corporation 2003. All rights reserved.
Trademarks Page 31 of 32
developerWorks
ibm.com/developerWorks
James Magowan James Magowan has spent 7 years with IBM working on leading edge customer facing projects. He has worked in High Performance Computing with large SP installations before playing with Linux clusters ahead of IBM's Linux strategy. He has recently worked on Grid Computing Projects since January 2001 including European DataGrid and OGSA-DAI (Open Grid Services Architecture - Database Access and Integration) and was heavily involved within the Global Grid Forum chairing two working groups. These Grid projects have given him experience with Service Orientated Architectures and Data Grids. He has been working with Web Services and Data Grids for the last 3 years.
Invoking Web services from SQL Copyright IBM Corporation 2003. All rights reserved.
Trademarks Page 32 of 32