Friday, September 12, 2008

Building a Web Service in Delphi with a DB2 Backend

Original Source click here

Level: Introductory

Marco Cantu (www.marcocantu.com.),

05 Dec 2002

To help you get started with Web services, the author shows you a practical Web service example built with Delphi and a test client that serves up data from an IBM DB2 Universal Database backend.
Show developerWorks content related to my search: DelphiShow developerWorks content related to my search: Delphi


© 2002 International Business Machines Corporation. All rights reserved.

Introduction

Among the many features of BorlandTM Delphi® and Kylix® that sets them apart from many other visual development tools, is the extensive support for the development of XML Web services server and client applications. Delphi Web services support is based on SOAP (Simple Object Access Protocol), the widespread technology for implementing Web services. (You can find more about SOAP at http://www.w3.org/TR/SOAP/.)

Web services are the main technology driving the shift towards B2B (business-to-business) applications. To help you get started with this technology, I'll show you a practical Web service example built with Delphi and a test client that serves up data from an IBM® DB2® Universal DatabaseTM backend.



Back to top


Creating a Web Service in Delphi

Borland first added Web services support to Delphi 6. Contrary to other approaches, this technology is integrated not only into the development environment but also in the language itself. The Delphi language has contained notion of "interface" for a long time now, similar to the corresponding JavaTM concept. Now, Borland has introduced support for introspection on interfaces, allowing for a generic mechanism of interface publishing and remote invocation. This has been tailored, in particular, to a SOAP mapping layer for a few ready-to-use components.

Having said this, let me show you how you can practically create a Web service in Delphi 7. Start a new project by using the File | New | Other menu command of the Delphi IDE, move to the WebServices tab of the New Items dialog box and choose SOAP Server Application.

As a Web service is typically deployed as a Web server extension, you have to decide what kind of Web server architecture is most suited for your application. With Delphi, you can choose between Apache modules (available also on Kylix, of course), CGI, ISAPI (only on Windows®, with a Microsoft IIS server), and the internal Web Application Debugger. The first thing to notice is that you aren't locked into any of these selections: your choice here impacts a few lines of code in the main project file, but has almost no effect at all on the development of the actual code of the Web server extension or Web service. The Delphi WebBroker architecture, in fact, abstracts the development of server side programs from the actual technology being used. You can move from one model to another simply by creating a new project and adding to it all of the source code files of an existing application.

For this example I'm using the Web App Debugger model. This model features a stand-alone executable activated by a custom Web server using a socket connection. The Web App Debugger application itself lets you trace the calls and see your applications HTTP requests and responses. Notice that you'll need to have this program running to test the server built in this article. The advantage of using this technology is that you can execute the server application from the Delphi IDE and immediately start debugging it without all of the fuss needed to debug an extension library of a Web server.

Now that I've picked a Web server architecture, Delphi wants to know if I'm interested in creating an interface for our Web service. I click the Yes button to activate the Interface Wizard. In this Wizard, I'll enter the name of the interface I'm creating, and the name of the file where I want to save it. This wizard helps create the proper architecture for the Web service, so it's a good idea to use it.



Back to top


The structure of the Web Service application

At the end of these steps, Delphi will generate the complete structure of a project for a Web service, including:

  • A SOAP data module, which hosts a few standard components.
  • An interface unit, which includes the definition of the Delphi interface to be exposed as a SOAP server.
  • An implementation unit for implementing the methods of the interface you want to expose.
  • A form, which represents a server, based on the Web Debugger architecture that is a full-blown Windows application. Of course we'll ignore the form, as this is only for development purpose.

Now that Delphi has generated this code, it's time to start developing the Web service. The first step is to define the methods of the interface. This is a core step, as it implies the definition of the capabilities of our Web service. You can take two approaches at tackling this step. The first is to use an existing WSDL (Web Service Description Language) file, importing it to generate the proper Delphi interface. I'll use this in my example in this article. The second approach is to define the interface in Delphi code and let one of the components added by default to the Web service data module, the WSDLHTMLPublish component, translate the Delphi interface into public WSDL.



Back to top


Defining the Web Service interface and WSDL

For this example, I want to build a Web service capable of exposing data about employees of a company. This Web service will be mapped to the EMPLOYEE table of the SAMPLE database included in DB2. The Delphi interface of the Web service is defined in the SoapEmployeeIntf unit (see the SoapEmployeeIntf.pas file of the source code) as follows:

 
type
ISoapEmployee = interface (IInvokable)
['{77D0D940-23EC-49A5-9630-ADE0751E3DB3}']
function GetEmployeeNames: string; stdcall; function GetEmployeeData (EmpID: string): string; stdcall;
end;

The unit also has some internal initialization code that registers the interface into an internal SOAP registry within the application. The effect of writing this interface is a WSDL file produced by the Web service application, and is described in an introductory page displayed when connecting to the Web service using a browser, as shown in Figure 1.


Figure 1.The description of the Web service displayed when you connect to it via a browser. One click and you'll be able to download the WSDL file describing the SOAP interface of this Web service.
Display of Web Service descriptions

Another unit, SoapEmployeeImpl, provides the implementation of this interface with this class:

 
type
TSoapEmployee = class(TInvokableClass, ISoapEmployee)
public
function GetEmployeeNames: string; stdcall;

function GetEmployeeData (EmpID: string): string;
stdcall;
end;

As you can see, the class inherits from the TInvokableClass of the Delphi library and implements the interface defined earlier. The actual implementation of the Web service lies in the two methods above and in some helper functions to manage the XML data being returned.



Back to top


Accessing a DB2 database

The dbExpressTM architecture provides access to a DB2 database, as discussed in the article by Bob Swart elsewhere on this site. This situation differs than the one Swart describes in that the datasets of my example only need to be read once, so I can safely use unidirectional datasets, with no caching whatsoever.

All of the connectivity and SQL is hosted in a data module, a container of non-visual components, defined by the following DFM file (reduced to the key elements in this listing):

 
object DataModule3: TDataModule3
object SQLConnection: TSQLConnection
ConnectionName = 'DB2Connection'
DriverName = 'DB2'
LoginPrompt = False
Params.Strings = (
'Database=SAMPLE'
'User_Name=***'
'Password=***')
VendorLib = 'db2cli.dll'
end
object dsEmplList: TSQLDataSet
CommandText = 'select EMPNO, LASTNAME, FIRSTNME from EMPLOYEE'
SQLConnection = SQLConnection
object dsEmplListEMPNO: TStringField
object dsEmplListLASTNAME: TStringField
object dsEmplListFIRSTNME: TStringField
end
object dsEmpData: TSQLDataSet
CommandText = 'select * from EMPLOYEE where EmpNo = :id'
Params = <
item
DataType = ftFixedChar
Name = 'id'
ParamType = ptInput
end>
SQLConnection = SQLConnection
end
end

The data module has two SQL queries hosted by SQLDatSet components. The first retrieves the name and ID of each employee, while the second returns the entire set of data for a given employee. The problem I face, however, is how to return this data to a remote client program. In this example I've returned XML documents, instead of working with complex SOAP data structures.



Back to top


Transforming to XML

In this example the GetEmployeeNames method creates an XML document with a list of employees, with their first and last names as values and the related database ID as an attribute. I've omitted the code of the helper functions MakeXmlStr and MakeXmlAttribute that you can find in the complete source code, available for download with this article:

 
function TSoapEmployee.GetEmployeeNames: string;
var
dm: TDataModule3;
begin
dm := TDataModule3.Create (nil);
try
dm.dsEmplList.Open;
Result := '<employeelist>' + sLineBreak;
while not dm.dsEmplList.EOF do
begin
Result := Result + ' ' + MakeXmlStr ('employee',
dm.dsEmplListLASTNAME.AsString + ' ' +
dm.dsEmplListFIRSTNME.AsString,
MakeXmlAttribute ('id', dm.dsEmplListEMPNO.AsString)) + sLineBreak;
dm.dsEmplList.Next;
end;
Result := Result + '</employeelist>';
finally
dm.Free;
end;
end;

The second method, GetEmployeeData, uses the parametric query and formats the resulting fields in separate XML nodes (using another helper function I've written and not listed here, FieldsToXml):

 
function TSoapEmployee.GetEmployeeData(EmpID: string): string;
var
dm: TDataModule3;
begin
dm := TDataModule3.Create (nil);
try
dm.dsEmpData.ParamByName('ID').AsString := EmpId;
dm.dsEmpData.Open;
Result := FieldsToXml ('employee', dm.dsEmpData);
finally
dm.Free;
end;
end;

Beside the fact that I've omitted a lot of minor details, some of which might be intriguing if you don't know Delphi and its class library, the code for the server side of the Web service is finished. You might wonder where the SOAP-related code is, but the answer is that there is none! As we've seen earlier for the WSDL, Delphi automatically provides the SOAP engine, using two components placed by the wizard in the SOAP data module, the HTTPSoapDispatcher and HTTPSoapPascalInvoker components.



Back to top


Writing a test client

Now that I have a Web service up and running, it's time to build a client that communicates with the server. This is usually accomplished by importing the WSDL file defining the Web service. In this specific case I have to convert the XML data we receive into something more manageable. I've used Delphi XMLMapper to convert the list of employees received from the Web service into a dataset I can visualize using a DBGrid. Tthe XMLMapper is a rather complex tool and I do not have space to cover it in this article. For the moment, just use the client program available in the article source code (and shown in Figure 2). In a future installment I'll give you the complete details of how you can write a SOAP client application with Delphi.


Figure 2. The client program used to test the Web service
The client program used to test the Web service


Back to top


Conclusion

In this article we have seen how easy it is to build a Web service in Delphi, connecting to a DB2 database to fetch the data. Although we have produced XML, I haven't covered all of the techniques Delphi provides to support database data to XML mapping, and there are quite a few. In this example, in fact, I've produced the XML directly. One important thing to notice is that the program I've produced is fully portable to a Linux server by recompiling it with Kylix and converting it from the debug version into an Apache module. This means there is a still a lot to cover in the area. Stay tuned!



0 Comments: