Sign in Join
Wiki copytemporary

Web Service Toolkit/fr: what changed

Revision 0 to 1. Removed lines have a minus sign; added lines have a plus sign.

Title: Web Service Toolkit/fr

OldNewLine
1+"Web Service Toolkit” is a web services package for FPC, Lazarus and Delphi; “Web Service Toolkit” is meant to ease web services consumption and creation by FPC, Lazarus and Delphi users.
2+
3+## Côté Client ( consommation de service )
4+
5+### Vue d'ensemble
6+
7+“Web Service Toolkit” est composé de deux parties :
8+
9+- un ensemble de programmes: “typ_lib_edtr” un éditeur de bibliothèques de types basé sur WSDL, un outil en ligne de commande “ws_helper” et un package d'intégration à Lazarus qui contient quelques assistants,
10+- une collection d'unités d'exécution (runtime).
11+
12+Etant donné un fichier de définition d'interface ( un fichier WSDL ou un fichier pascal décrivant un service web), “ws_helper” ( ou depuis Lazarus, l'assistant d'importation de fichier WSDL ) va créer une unité pascal object contenant un proxy implémentant cette interface. A l'exécution quand un un appel ciblant le service web sera émis, le rôle du proxy est de :
13+
14+- sérialiser (marshall) les paramètres d'appel,
15+- faire l'appel au service web ciblé,
16+- recevoir le retour d'appel et désérialiser (unmarshall) les paramètres de sortie vers l'apellant.
17+
18+En coulisses, le proxy va prendre soin des détails de la "plomberie" de SOAP.
19+
20+### Exemple
21+
22+Nous allons utiliser le “Amazon E-Commerce Service”, disponible librement ( vous aurez à créer un compte, c'est gratuit ) pour un usage personnel à cette adresse[1](http://www.amazon.com/gp/browse.html?node=3435361). Afin d'utiliser ce service, nous avons à télécharger ses interfaces WSDL exposées (Web Services Description Language) et les traduire en langage Pascal. Pour cela, depuis Lazarus nous pouvons utiliser l'assistant d'import; nous pouvons aussi utiliser ws_helper comme programme indépendant.
23+
24+#### L'assistant “WSDL importer”
25+
26+Cet assistant est contenu dans le paquet wst_design.lpk situé dans le dossier \ide\lazarus du toolkit. Une fois ce paquet installé, il ajoute une section de menu “Web Services Toolkit” avec deux (2) sous-menus au menu Lazarus “Project” :
27+
28+- Import WSDL File ...
29+- Type Library Editor ...
30+
31+![](/wiki-images/b/b8/Wst_lazarus_menu.PNG)
32+
33+Cliquez sur le premier élément de menu (Importer Fichier WSDL ...), cela fera apparaître le dialogue ci-dessous. Nous spécifions le fichier WSDL et le dossier où stocker les fichiers générés et cliquez sur le bouton OK pour finir.
34+
35+![](/wiki-images/2/24/Wst_lazarus_importer.PNG)
36+
37+Cela va produire deux (2) fichiers source pascal :
38+
39+- AWSECommerceService.pas, le fichier de définition du service ( équivalent Pascal du fichier WSDL )
40+- AWSECommerceService_proxy.pas, ce fichier contient un proxy qui implémente l'interface du service définie dans le premier fichier.
41+
42+#### Import par ws_helper.
43+
44+Le programme **ws_helper** est une version en ligne de commande de l'assistant d'import. Afin de présenter ses capacités, les arguments de ligne de commande qu'il supporte sont sont affichées ci-dessous.
45+
46+ ws_helper [-uMODE] [-p] [-b] [-i] [-oPATH] inputFilename
47+ -u MODE Generate the pascal translation of the WSDL input file
48+ MODE value may be U for used types or A for all types
49+ -p Generate service proxy
50+ -b Generate service binder
51+ -i Generate service minimal implementation
52+ -o PATH Relative output directory
53+ -a PATH Absolute output directory
54+
55+Pour traduire le fichier WDSL téléchargé depuis le site web "Amazon E-Commerce Service” exécutez la commande suivante à l'invite:
56+
57+ ..\..\ws_helper\ws_helper.exe -uA -p -o. AWSECommerceService.wsdl
58+ ws_helper, Web Service Toolkit 0.4 Copyright (c) 2006, 2007 by Inoussa OUEDRAOGO
59+
60+ Parsing the file : AWSECommerceService.wsdl
61+ (...)
62+ Interface file generation...
63+ Proxy file generation...
64+ Metadata file generation...
65+ File "AWSECommerceService.wsdl" parsed succesfully.
66+
67+ci-dessous est affiché un extrait des deux fichiers :
68+
69+``` pascal
70+unit AWSECommerceService;
71+{$IFDEF FPC} {$mode objfpc}{$H+} {$ENDIF}
72+interface
73+
74+uses SysUtils, Classes, TypInfo, base_service_intf, service_intf;
75+
76+const
77+ sNAME_SPACE = 'http://webservices.amazon.com/AWSECommerceService/2007-04-04';
78+ sUNIT_NAME = 'AWSECommerceService';
79+
80+type
81+
82+ HelpRequest = class;
83+ Help_RequestArray = class;
84+
85+(...)
86+
87+ AWSECommerceServicePortType = interface(IInvokable)
88+ ['{305A7E48-DD92-4C20-B699-4F2B47C93342}']
89+ function Help(
90+ Const HelpParam : Help_Type
91+ ):HelpResponse_Type;
92+ function ItemSearch(
93+ Const ItemSearchParam : ItemSearch_Type
94+ ):ItemSearchResponse_Type;
95+ function ItemLookup(
96+ Const ItemLookupParam : ItemLookup_Type
97+ ):ItemLookupResponse_Type;
98+ (...)
99+ end;
100+
101+ procedure Register_AWSECommerceService_ServiceMetadata();
102+```
103+
104+``` pascal
105+Unit AWSECommerceService_proxy;
106+{$IFDEF FPC} {$mode objfpc}{$H+} {$ENDIF}
107+Interface
108+
109+Uses SysUtils, Classes, TypInfo, base_service_intf, service_intf, AWSECommerceService;
110+
111+Type
112+
113+ TAWSECommerceServicePortType_Proxy=class(TBaseProxy,AWSECommerceServicePortType)
114+ Protected
115+ class function GetServiceType() : PTypeInfo;override;
116+ function Help(
117+ Const HelpParam : Help_Type
118+ ):HelpResponse_Type;
119+ function ItemSearch(
120+ Const ItemSearchParam : ItemSearch_Type
121+ ):ItemSearchResponse_Type;
122+ function ItemLookup(
123+ Const ItemLookupParam : ItemLookup_Type
124+ ):ItemLookupResponse_Type;
125+ (...)
126+ End;
127+
128+ Function wst_CreateInstance_AWSECommerceServicePortType(
129+ const AFormat : string = 'SOAP:';
130+ const ATransport : string = 'HTTP:'
131+ ):AWSECommerceServicePortType;
132+
133+Implementation
134+uses wst_resources_imp, metadata_repository;
135+
136+Function wst_CreateInstance_AWSECommerceServicePortType(
137+ const AFormat : string;
138+ const ATransport : string
139+):AWSECommerceServicePortType;
140+Begin
141+ Result := TAWSECommerceServicePortType_Proxy.Create(
142+ 'AWSECommerceServicePortType',
143+ AFormat +
144+ GetServiceDefaultFormatProperties(TypeInfo(AWSECommerceServicePortType)),
145+ ATransport + 'address=' + GetServiceDefaultAddress(TypeInfo(AWSECommerceServicePortType))
146+ );
147+End;
148+
149+function TAWSECommerceServicePortType_Proxy.ItemSearch(
150+ Const ItemSearchParam : ItemSearch_Type
151+):ItemSearchResponse_Type;
152+Var
153+ locSerializer : IFormatterClient;
154+ strPrmName : string;
155+Begin
156+ locSerializer := GetSerializer();
157+ Try
158+ locSerializer.BeginCall('ItemSearch', GetTarget(),(Self as ICallContext));
159+ locSerializer.Put('ItemSearch', TypeInfo(ItemSearch_Type), ItemSearchParam);
160+ locSerializer.EndCall();
161+
162+ MakeCall();
163+
164+ locSerializer.BeginCallRead((Self as ICallContext));
165+ TObject(Result) := Nil;
166+ strPrmName := 'ItemSearchResponse';
167+ locSerializer.Get(TypeInfo(ItemSearchResponse_Type), strPrmName, Result);
168+
169+ Finally
170+ locSerializer.Clear();
171+ End;
172+End;
173+(...)
174+```
175+
176+Noous avons maintenant la possibilité de construire un programme simple pour le service. La bibliothèque Synapse est requise pour compiler le programme pour qu'il soit utilisé pour les communications HTTP. Cette bibliothèque est téléchargeable gratuitement à cette adresse: [2](http://synapse.ararat.cz/). La bibliothèque Indy[3](http://www.indyproject.org/Sockets/fpc/index.en.html) ou la bibliothèque ICS[4](http://www.overbyte.be/frame_index.html) peuvent aussi être utilisées.
177+
178+``` pascal
179+program amazon_sample;
180+{$mode objfpc}{$H+}
181+uses
182+ Classes, SysUtils, soap_formatter, synapse_http_protocol,
183+ metadata_repository, AWSECommerceService, AWSECommerceService_proxy;
184+
185+const sACCES_ID = <Your AccesID here>;
186+
187+function ReadEntry(const APromp : string):string ;
188+begin
189+ Result := '';
190+ Write(APromp);
191+ while True do begin
192+ ReadLn(Result);
193+ Result := Trim(Result);
194+ if ( Length(Result) > 0 ) then
195+ Break;
196+ end;
197+end;
198+
199+var
200+ locService : AWSECommerceServicePortType;
201+ rqst : ItemSearch_Type;
202+ rsps : ItemSearchResponse_Type;
203+ rspsItem : Items_Type;
204+ i, j, k : Integer;
205+ itm : Item_Type;
206+begin
207+ SYNAPSE_RegisterHTTP_Transport();
208+ WriteLn('Web Services Toolkit Amazon sample');
209+ WriteLn('This sample demonstrates the "ItemSearch" method of the Amazon web service');
210+ WriteLn();
211+ rqst := ItemSearch_Type.Create();
212+ try
213+ locService := wst_CreateInstance_AWSECommerceServicePortType();
214+ rqst.AWSAccessKeyId := sACCES_ID;
215+ while True do begin
216+ rqst.Request.SetLength(1);
217+ rqst.Request[0].SearchIndex := ReadEntry('Enter the Search Index : ');
218+ rqst.Request[0].Availability := Available;
219+ rqst.Request[0].Count := 10;
220+ rqst.Request[0].MerchantId := 'Amazon';
221+ rqst.Request[0].ItemPage := 1;
222+ rqst.Request[0].Keywords := ReadEntry('Enter the Keywords : ');
223+ rsps := locService.ItemSearch(rqst);
224+ if ( rsps.OperationRequest.Errors.Length > 0 ) then begin
225+ WriteLn(Format('Errors ( %d ) : ',[rsps.OperationRequest.Errors.Length]));
226+ for i := 0 to Pred(rsps.OperationRequest.Errors.Length) do begin
227+ WriteLn(Format(' Error[%d] :',[i]));
228+ WriteLn(' ' + rsps.OperationRequest.Errors[i].Code);
229+ WriteLn(' ' + rsps.OperationRequest.Errors[i].Message);
230+ end;
231+ end else begin
232+ WriteLn(Format('Response ( %d ) : ',[rsps.Items.Length]));
233+ if Assigned(rsps) then begin
234+ for i := 0 to Pred(rsps.Items.Length) do begin
235+ rspsItem := rsps.Items[i];
236+ WriteLn(' TotalPages :' + IntToStr(rspsItem.TotalPages));
237+ WriteLn(' TotalResults :' + IntToStr(rspsItem.TotalResults));
238+ WriteLn(' Items :' + IntToStr(rspsItem._Item.Length));
239+ WriteLn('');
240+ for j := 0 to Pred(rspsItem._Item.Length) do begin
241+ itm := rspsItem._Item[j];;
242+ WriteLn(' ASIN :' + itm.ASIN);
243+ WriteLn(' DetailPageURL :' + itm.DetailPageURL);
244+ if Assigned(itm.ItemAttributes) then begin
245+ WriteLn(' Title :' + itm.ItemAttributes.Title);
246+ for k := 0 to Pred(itm.ItemAttributes.Author.Length) do begin
247+ WriteLn(' Author[ ' + IntToStr(k) + ' ] ' + itm.ItemAttributes.Author.Item[k]);
248+ end;
249+ WriteLn(' Manufacturer :' + itm.ItemAttributes.Manufacturer);
250+ WriteLn(' ProductGroup :' + itm.ItemAttributes.ProductGroup);
251+ end;
252+ WriteLn('');
253+ end;
254+ end;
255+ end else begin
256+ WriteLn('Unexpected service response : Invalid response');
257+ end;
258+ end;
259+ WriteLn();
260+ WriteLn();
261+ if ( UpperCase(ReadEntry('Continue ( Y/N ) :'))[1] <> 'Y' ) then
262+ Break;
263+ end;
264+ finally
265+ FreeAndNil(rqst);
266+ FreeAndNil(rsps);
267+ end;
268+ ReadLn;
269+end.
270+```
271+
272+Les unités base_service_intf, service_intf, soap_formatter, synapse_http_protocol, wst_resources_imp et metadata_repository sont fournies avec le toolkit; Ci-dessous le résultat d'une session d'exécution de recherche de “Freepascal” dans l'index de recherche “All” ( le service est sensible à la casse des caractères!) .
273+
274+ Web Services Toolkit Amazon sample
275+ This sample demonstrates the "ItemSearch" method of the Amazon web service
276+
277+ Enter the Search Index : All
278+ Enter the Keywords : Freepascal
279+ Response ( 1 ) :
280+ TotalPages :1
281+ TotalResults :9
282+ Items :9
283+
284+ ASIN :0470088702
285+ DetailPageURL : http://www.amazon.com/gp/redirect.html%3FASIN=0470088702%26tag=ws%26lcode=sp1%26cID=2025%26ccmID=165953%26location=/o/ASIN/0470088702%253FSubscriptionId=0W3H25JMMGBNBXSTQN82
286+ Title :Beginning Programming For Dummies (Beginning Programming f
287+ or Dummies)
288+ Author[ 0 ] Wallace Wang
289+ Manufacturer :For Dummies
290+ ProductGroup :Book
291+
292+ ASIN :0471375233
293+ DetailPageURL : http://www.amazon.com/gp/redirect.html%3FASIN=0471375233%26tag=ws%26lcode=sp1%26cID=2025%26ccmID=165953%26location=/o/ASIN/0471375233%253FSubscriptionId=0W3H25JMMGBNBXSTQN82
294+ Title :Assembly Language Step-by-step: Programming with DOS and Linux (with CD-ROM)
295+ Author[ 0 ] Jeff Duntemann
296+ Manufacturer :Wiley
297+ ProductGroup :Book
298+ (...)
299+
300+Cela trouve une (1) page contenant neuf (9) items! La fonction wst_CreateInstance_AWSECommerceServicePortType(), située dans le fichier AWSECommerceService.pas crée une instance de proxy basé sur les informations du service contenu dans le fichier WSDL.
301+
302+``` pascal
303+Function wst_CreateInstance_AWSECommerceServicePortType(
304+ const AFormat : string;
305+ const ATransport : string
306+):AWSECommerceServicePortType;
307+Begin
308+ Result := TAWSECommerceServicePortType_Proxy.Create(
309+ 'AWSECommerceServicePortType',
310+ Aformat + GetServiceDefaultFormatProperties(TypeInfo(AWSECommerceServicePortType)),
311+ ATransport + 'address=' + GetServiceDefaultAddress(TypeInfo(AWSECommerceServicePortType))
312+ );
313+End;
314+```
315+
316+Le code source complet de l'exemple d'Amazon est situé dans le dossier \samples\amazon pour fpc; L'exemple Delphi est situé dans le dossier \samples\delphi\amazon.
317+
318+### Paramètres de Connection
319+
320+Le format général est:
321+
322+ protocol:paramName=paramValue(;paramName=paramValue)*
323+
324+#### Paramètres de Proxy HTTP Proxy
325+
326+Pour HTTP, les paramètres supportés sont les suivants:
327+
328+- Address **( required for a service supporting a unique address )**
329+- ProxyServer
330+- ProxyPort
331+- ProxyUsername
332+- ProxyPassword
333+
334+Les connexions HTTP via un proxy sont supportées. Ci-dessous un exemple de chaîne d'adresse.
335+
336+``` pascal
337+ const
338+ sADDRESS = 'http:address=http://webservices.amazon.com/AWSECommerceService/2007-04-04'+
339+ ';ProxyServer=197.150.10.10;ProxyPort=9881'+
340+ ';ProxyUsername=inoussa;ProxyPassword=wst';
341+```
342+
343+Le toolkit a deux implémentations TCP basées sur Synapse ( synapse_tcp_protocol.pas ) et ICS ( ics_tcp_protocol.pas ).
344+
345+#### Paramètres de connexion TCP
346+
347+Les paramètres TCP supportés sont:
348+
349+- address ( requis pour un service supportant une adresse unique )
350+- Port
351+- target( le service cible )
352+
353+Ci-dessous un exemple de chaîne d'adresse.
354+
355+``` pascal
356+ Const
357+ sADDRESS = 'TCP:Address=10.0.0.3;Port=1234;target=UserService';
358+```
359+
360+The toolkit has two TCP implementations based on Synapse ( synapse_tcp_protocol.pas ) and ICS ( ics_tcp_protocol.pas ).
361+
362+#### Paramètres de connexion LIBRARY ( LIB )
363+
364+L'idée derrière ce protocole est d'être capable d'héberger des services dans des bibliothèques dynamiques ( DLL/DSO ). Cela peut -être vu comme un framework à plugins où les where plugins ( services ) sont fournis par des bibliothèques dynamiques. Les paramètres de LIB supportés sont:
365+
366+- FileName ( le nom du fichier DLL/SO )
367+- target( le service cible )
368+
369+Ci-dessous un exemple de chaîne d'adresse.
370+
371+``` pascal
372+ Const
373+ sADDRESS = 'LIB:FileName=..\library_server\lib_server.dll;target=UserService';
374+```
375+
376+Le toolkit a une implémentation LIB ( library_protocol.pas ).
377+
378+***Le dossier d'exemples contient 4 projets user_client_console, tcp_server, http_server et library_server qui font la démonstration des protocoles TCP, HTTP et LIBRARY.***
379+
380+#### Service Multi-Adresses ( une adresse par opération )
381+
382+Certains services ( comme les services SOAP eBay ) utilisent une adresse par opération. Le toolkit utilise des meta data étendues ( voir les meta data de services au chapitre précédent ) pour choisir les adresses des opération. L'exemple SOAP “ebay” situé dans le dossier tests\ebay fait la démonstration de la configuration de l'adresse par opération.
383+
384+## Server Side ( service creation )
385+
386+### Overview
387+
388+Web Service Toolkit contains a server side framework and a WSDL based type library editor for service creation. Key features are:
389+
390+- Service definition ( interface ) is separated from implementation,
391+- Interface and implementations are not bound to message protocol,
392+- WSDL generation
393+- Support for SOAP 1.1 serialization
394+- Support for XMLRPC serialization
395+- Support for custom binary serialization
396+- The framework is not bound to a transport protocol
397+- Easy to add support for application servers.
398+
399+### Example
400+
401+In order to create a service, we have to :
402+
403+- define its interface,
404+- provide an implementation and register that one for the service,
405+- provide a binder that will route calls targeting the service to the implementation and register that one,
406+- host the service into an application server( TCP server, HTTP Server, LIBRARY server, ... ).
407+
408+#### Defining the service Interface
409+
410+Starting from the 0.5 version, the WST provides a WSDL based Type library Editor to define types and services used by an implementation. The figure (3) below presents the general interface of this tool. The Type library Editor is provided as
411+
412+- a Lazarus wizard as a menu item “Project/Web Services Toolkit/Type Library Editor..”
413+- a standalone program typ_lib_edtr.exe.
414+
415+![](/wiki-images/0/0a/Wst_type_lib_edtr.PNG)
416+
417+Type Library Editor features:
418+
419+- Graphical user interface
420+- WSDL source view
421+- Pascal source view of the library
422+- Pascal Proxy source view
423+- Pascal implementation skeleton source view
424+- Pascal Proxy binder view
425+- enumeration creation interface
426+- class creation interface
427+- array creation interface
428+- type alias creation interface
429+- service interface creation interface.
430+
431+Below are showed some sample images. We will use the user_service_intf.wsdl file located in the \samples directory for our sample.
432+
433+![](/wiki-images/b/ba/Wst_class_editor.PNG)
434+
435+![](/wiki-images/f/f6/Wst_interface_editor.PNG)
436+
437+##### Export the pascal files.
438+
439+The Type Library Editor has option to generate the pascal version of the WSDL file. To do so, click on the “Files\Save generated files ...” ( it can also be done through the contextual menu ); It will bring up the dialog box showed in the following image. ![Web Services Toolkit Type library editor, exporting to pascal files.](/wiki-images/c/c7/Wst_type_library_export.PNG)
440+
441+Click OK the button to complete. The program **ws_helper** has the same capabilities and the files can be generated with the following command :
442+
443+ ws_helper\ws_helper.exe -i -b -o. user_service_intf.pas
444+ ws_helper, Web Service Toolkit 0.5 Copyright (c) 2006, 2007 by Inoussa OUEDRAOGO
445+ Parsing the file : user_service_intf.wsdl
446+ Information : Parsing "tns:TUserArray" ...
447+ Information : Parsing "tns:TUser" ...
448+ Information : Parsing "tns:TUser" ...
449+ Information : Parsing "xsd:string" ...
450+ Information : Parsing "tns:TUser" ...
451+ Information : Parsing "xsd:string" ...
452+ Information : Parsing "xsd:boolean" ...
453+ Information : Parsing "TUserArray" ...
454+ Information : Parsing "TUser" ...
455+ Information : Parsing "TUserCategory" ...
456+ Information : Parsing "TNote" ...
457+ Interface file generation...
458+ Proxy file generation...
459+ Metadata file generation...
460+ File "user_service_intf.wsdl" parsed succesfully.
461+
462+The complete projects of the example is located in the folder “samples”. Below is printed a extract of the generated interface file.
463+
464+``` pascal
465+unit user_service_intf;
466+{$IFDEF FPC} {$mode objfpc}{$H+} {$ENDIF}
467+interface
468+
469+uses SysUtils, Classes, TypInfo, base_service_intf, service_intf;
470+
471+const
472+ sNAME_SPACE = 'urn:UserService';
473+ sUNIT_NAME = 'user_service_intf';
474+
475+type
476+
477+ TUser = class;
478+ TUserArray = class;
479+
480+ TUserCategory = (
481+ Normal
482+ ,Admin
483+ );
484+
485+ TUser = class(TBaseComplexRemotable)
486+ published
487+ property Category : TUserCategory read FCategory write FCategory;
488+ property UserName : string read FUserName write FUserName;
489+ property eMail : string read FeMail write FeMail;
490+ property Preferences : string read FPreferences write FPreferences;
491+ property Note : TNote read FNote write FNote;
492+ end;
493+
494+ TUserArray = class(TBaseObjectArrayRemotable)
495+ private
496+ function GetItem(AIndex: Integer): TUser;
497+ public
498+ class function GetItemClass():TBaseRemotableClass;override;
499+ property Item[AIndex:Integer] : TUser Read GetItem;Default;
500+ end;
501+
502+ UserService = interface(IInvokable)
503+ ['{CA6F6192-C3DE-4D9C-B3DF-E616376A0DC9}']
504+ function GetList():TUserArray;
505+ procedure Add(
506+ Const AUser : TUser
507+ );
508+ procedure Update(
509+ Const AUser : TUser
510+ );
511+ function Find(
512+ Const AName : string
513+ ):TUser;
514+ function Delete(
515+ Const AName : string
516+ ):boolean;
517+ end;
518+(...)
519+```
520+
521+#### Providing an implementation for the service
522+
523+The user_service_intf_imp.pas unit generated above contains a skeleton implementation class for the interface. It defines a procedure named RegisterUserServiceImplementationFactory. The procedure registers the class as the service implementation provider in the implementation registry.
524+
525+``` pascal
526+Unit user_service_intf_imp;
527+{$IFDEF FPC} {$mode objfpc}{$H+} {$ENDIF}
528+Interface
529+Uses SysUtils, Classes,
530+ base_service_intf, server_service_intf, server_service_imputils,
531+ user_service_intf, cursor_intf;
532+
533+Type
534+ { TUserService_ServiceImp }
535+
536+ TUserService_ServiceImp=class(TBaseServiceImplementation,UserService)
537+ Protected
538+ function GetList():TUserArray;
539+ procedure Add(
540+ Const AUser : TUser
541+ );
542+ procedure Update(
543+ Const AUser : TUser
544+ );
545+ function Find(
546+ Const AName : string
547+ ):TUser;
548+ function Delete(
549+ Const AName : string
550+ ):boolean;
551+ End;
552+
553+ procedure RegisterUserServiceImplementationFactory();
554+
555+Implementation
556+(...)
557+
558+procedure TUserService_ServiceImp.Add(Const AUser : TUser);
559+var
560+ locObj : TUser;
561+Begin
562+ locObj := Find(AUser.UserName);
563+ if ( locObj <> nil ) then
564+ raise Exception.CreateFmt('Duplicated user : "%s"',[AUser.UserName]);
565+ locObj := TUser.Create();
566+ locObj.Assign(AUser);
567+ FUserList.Add(locObj);
568+End;
569+
570+procedure RegisterUserServiceImplementationFactory();
571+Begin
572+ GetServiceImplementationRegistry().Register(
573+ 'UserService',
574+TImplementationFactory.Create(TUserService_ServiceImp) as IServiceImplementationFactory);
575+End;
576+
577+(...)
578+```
579+
580+“ws_helper” has options to generate proxy file, basic implementation skeleton file and a binder file ( see the following listing).
581+
582+ ws_helper, Web Service Toolkit 0.4 Copyright (c) 2006, 2007 by Inoussa OUEDRAOGO
583+ ws_helper [-uMODE] [-p] [-b] [-i] [-oPATH] inputFilename
584+ -u MODE Generate the pascal translation of the WSDL input file
585+ MODE value may be U for used types or A for all types
586+ -p Generate service proxy
587+ -b Generate service binder
588+ -i Generate service minimal implementation
589+ -o PATH Relative output directory
590+ -a PATH Absolute output directory
591+
592+The starting implementation file could also be create using **ws_helper** with the -i and -b options as above;
593+
594+ ws_helper\ws_helper.exe -i -b -o. user_service_intf.wsdl
595+ ws_helper, Web Service Toolkit 0.4 Copyright (c) 2006, 2007 by Inoussa OUEDRAOGO
596+ Parsing the file : user_service_intf.wsdl
597+ Proxy file generation...
598+ Binder file generation...
599+ Implementation file generation...
600+ Metadata file generation...
601+ File "user_service_intf.wsdl" parsed succesfully..
602+
603+#### Providing a binder for the service.
604+
605+The binder's role is to:
606+
607+- unpack the incoming message,
608+- set up the call stack,
609+- make the call against the registered implementation,
610+- serialize the execution stack to create the return message.
611+
612+The user_service_intf_binder.pas unit generated above, contains :
613+
614+- TUserService_ServiceBinder : the actual binder class,
615+- TUserService_ServiceBinderFactory a factory class for the binder and
616+- Server_service_RegisterUserServiceService : the binder factory registration procedure.
617+
618+The following code extract shows the unit interface part and a method handler of the binder.
619+
620+``` pascal
621+unit user_service_intf_binder;
622+{$IFDEF FPC} {$mode objfpc}{$H+} {$ENDIF}
623+interface
624+uses SysUtils, Classes, base_service_intf, server_service_intf, user_service_intf;
625+
626+type
627+ TUserService_ServiceBinder=class(TBaseServiceBinder)
628+ Protected
629+ procedure GetListHandler(AFormatter:IFormatterResponse);
630+ procedure AddHandler(AFormatter:IFormatterResponse);
631+ procedure UpdateHandler(AFormatter:IFormatterResponse);
632+ procedure FindHandler(AFormatter:IFormatterResponse);
633+ procedure DeleteHandler(AFormatter:IFormatterResponse);
634+ Public
635+ constructor Create();
636+ End;
637+
638+ TUserService_ServiceBinderFactory = class(TInterfacedObject,IItemFactory)
639+ protected
640+ function CreateInstance():IInterface;
641+ End;
642+
643+ procedure Server_service_RegisterUserServiceService();
644+
645+(...)
646+
647+procedure TUserService_ServiceBinder.AddHandler(AFormatter:IFormatterResponse);
648+Var
649+ cllCntrl : ICallControl;
650+ tmpObj : UserService;
651+ callCtx : ICallContext;
652+ strPrmName : string;
653+ procName,trgName : string;
654+ AUser : TUser;
655+Begin
656+ callCtx := GetCallContext();
657+ TObject(AUser) := Nil;
658+
659+ strPrmName := 'AUser'; AFormatter.Get(TypeInfo(TUser),strPrmName,AUser);
660+ If Assigned(Pointer(AUser)) Then
661+ callCtx.AddObjectToFree(TObject(AUser));
662+
663+ tmpObj := Self.GetFactory().CreateInstance() as UserService;
664+ if Supports(tmpObj,ICallControl,cllCntrl) then
665+ cllCntrl.SetCallContext(GetCallContext());
666+
667+ tmpObj.Add(AUser);
668+
669+ procName := AFormatter.GetCallProcedureName();
670+ trgName := AFormatter.GetCallTarget();
671+ AFormatter.Clear();
672+ AFormatter.BeginCallResponse(procName,trgName);
673+ AFormatter.EndCallResponse();
674+
675+ callCtx := Nil;
676+End;
677+```
678+
679+#### Host the service into an application server.
680+
681+The application server's role is to route incoming service requests to the Web Service Toolkit runtime. For the runtime to process service requests :
682+
683+- The services and their implementations have to be registered ,
684+- The message protocol (SOAP, binary,...) have to be registered.
685+
686+The runtime interface is defined in the server_service_intf unit. This unit contains :
687+
688+- GetServerServiceRegistry, which returns the service registry,
689+- GetServiceImplementationRegistry which returns the service implementation registry,
690+- GetFormatterRegistry which returns the message format registry and
691+- HandleServiceRequest which is the unique entry point for request processing.
692+
693+Starting from the version 0.5, the toolkit provides a simplified model to develop applications server . This is achieved using the listener classes. A listener implements a transport between the server and its clients. The toolkit provides three (3) listeners implementations:
694+
695+- TwstIndyHttpListener ( indy_http_server.pas ),
696+- TwstIndyTcpListener ( indy_tcp_server.pas ) and
697+- TwstSynapseTcpListener ( synapse_tcp_server.pas ).
698+
699+All listeners derive from TwstListener defined in the server_listener.pas file.
700+
701+Below is printed a Indy based HTTP server sample. The code is divided into three (3) parts :
702+
703+- messaging format registration :
704+
705+``` pascal
706+ Server_service_RegisterSoapFormat();
707+ Server_service_RegisterXmlRpcFormat();
708+ Server_service_RegisterBinaryFormat() ;
709+```
710+
711+- service implementation and binder registration :
712+
713+``` pascal
714+ RegisterUserServiceImplementationFactory();
715+ Server_service_RegisterUserServiceService();
716+```
717+
718+- the listner creation and starting : the listener is created and started by the lines
719+
720+``` pascal
721+ AppObject := TwstIndyHttpListener.Create();
722+ AppObject.Start();
723+```
724+
725+Complete listing :
726+
727+``` pascal
728+program http_server;
729+{$mode objfpc}{$H+}
730+uses
731+ {$IFDEF UNIX}{$IFDEF UseCThreads}
732+ cthreads,
733+ {$ENDIF}{$ENDIF}
734+ Classes, SysUtils,
735+ indy_http_server, metadata_service, logger_extension, server_listener,
736+ server_service_soap, server_binary_formatter, server_service_xmlrpc, config_objects,
737+ user_service_intf, user_service_intf_binder, user_service_intf_imp;
738+var
739+ AppObject : TwstListener;
740+begin
741+ Server_service_RegisterBinaryFormat();
742+ Server_service_RegisterSoapFormat();
743+ Server_service_RegisterXmlRpcFormat();
744+
745+ RegisterUserServiceImplementationFactory();
746+ Server_service_RegisterUserServiceService();
747+ AppObject := TwstIndyHttpListener.Create();
748+ try
749+ WriteLn('"Web Service Toolkit" HTTP Server sample listening at:');
750+ WriteLn('');
751+ WriteLn('http://127.0.0.1:8000/');
752+ WriteLn('');
753+ WriteLn('Press enter to quit.');
754+ AppObject.Start();
755+ ReadLn();
756+ finally
757+ FreeAndNil(AppObject);
758+ end;
759+end.
760+```
761+
762+Server_service_RegisterUserServiceService located in the user_service_intf_binder unit ( generated by ws_helper ) registers the UserService service by calling in turn GetServerServiceRegistry:
763+
764+``` pascal
765+procedure Server_service_RegisterUserServiceService();
766+Begin
767+ GetServerServiceRegistry().Register(
768+ 'UserService',TUserService_ServiceBinderFactory.Create() as IitemFactory
769+ );
770+End;
771+```
772+
773+Server_service_RegisterSoapFormat located in the server_service_soap unit ( provided by the toolkit ) registers the SOAP implementation by calling in turn GetFormatterRegistry:
774+
775+``` pascal
776+ procedure Server_service_RegisterSoapFormat();
777+ begin
778+ GetFormatterRegistry().Register(
779+ sPROTOCOL_NAME,
780+ sSOAP_CONTENT_TYPE,
781+ TSimpleItemFactory.Create(TSOAPFormatter) as IitemFactory
782+ );
783+ RegisterStdTypes();
784+ end;
785+```
786+
787+Server_service_RegisterBinaryFormat located in the server_binary_formatter unit ( provided by the toolkit ) registers the Binary message implementation by calling in turn GetFormatterRegistry:
788+
789+``` pascal
790+ procedure Server_service_RegisterBinaryFormat();
791+ begin
792+ GetFormatterRegistry().Register(
793+ sPROTOCOL_NAME,
794+ sBINARY_CONTENT_TYPE,
795+ TBinaryFormatterFactory.Create() as IitemFactory
796+ );
797+ end;
798+```
799+
800+Server_service_RegisterXmlRpcFormat located in the server_service_xmlrpc unit ( provided by the toolkit ) registers the XMLRPC message implementation by calling in turn GetFormatterRegistry:
801+
802+``` pascal
803+ procedure Server_service_RegisterXmlRpcFormat();
804+ begin
805+ GetFormatterRegistry().Register(
806+ sPROTOCOL_NAME,
807+ sXMLRPC_CONTENT_TYPE,
808+ TSimpleItemFactory.Create(TXmlRpcFormatter) as IItemFactory
809+ );
810+ end;
811+```
812+
813+In order to give it a try one have to :
814+
815+1. compile the server ( \samples\tcp_server\tcp_server.lpi it is a console program),
816+2. compile the client application ( \samples\user_client_console\user_client_console.lpi ),
817+3. execute the server and start listening,
818+4. execute the client.
819+
820+### WSDL generation
821+
822+Services in the toolkit are organized into meta data repositories. Conceptually a repository corresponds :
823+
824+- at compile time to the pascal unit containing the service definition
825+- at runtime to a name space.
826+
827+The repository is the toolkit WSDL generation unit.
828+
829+#### The Metadata Service
830+
831+The toolkit is provided with an easy to use metadata service implementation which in turn uses the raw interface defined in the metadata_repository unit (see above). A Lazarus GUI client application is located in the **tests\metadata_browser** folder.
832+
833+#### WSDL generation API
834+
835+The **metadata_wsdl** pascal unit contains the **GenerateWSDL** function for WSDL generation from a repository (see the signature below).
836+
837+``` pascal
838+ PServiceRepository = ^TServiceRepository;
839+ TServiceRepository = record
840+ NameSpace : ShortString;
841+ Name : ShortString;
842+ RootAddress : ShortString;
843+ ServicesCount : Byte;
844+ Services : PService;
845+ end;
846+
847+ procedure GenerateWSDL(AMdtdRep : PServiceRepository; ADoc : TDOMDocument);
848+```
849+
850+##### WSDL Customization
851+
852+The WSDL generation is based on the **IWsdlTypeHandler** and the **IWsdlTypeHandlerRegistry** interfaces located in the **metadata_wsdl** unit. In order to customize the generated WSDL, one has to provide a class implementing the **IWsdlTypeHandler** interface. Then that class has to be registered in the registry. The **metadata_wsdl** unit contains implementations for pascal enumerations, **TBaseComplexRemotable** descendants, and **TBaseArrayRemotable** descendants.
853+
854+#### Sample
855+
856+A functional sample project is located under **\samples\http_server** . It is an Indy base http server.
857+
858+### Services Extensions
859+
860+Services extensions provide a mean to hook into all the services request processing stages. Services extensions may be used, for example, to implement authentication, request logging, data compression, etc. The **IServiceExtension** bellow is the interface used by the toolkit runtime to call services extensions.
861+
862+``` pascal
863+ TMessageStage = (
864+ msAfterDeserialize, msAfterSerialize, msBeforeDeserialize, msBeforeSerialize
865+ );
866+
867+ IServiceExtension = interface
868+ ['{E192E6B3-7932-4D44-A8AC-135D7A0B8C93}']
869+ procedure ProcessMessage(
870+ const AMessageStage : TMessageStage;
871+ ACallContext : ICallContext;
872+ AMsgData : IInterface
873+ );
874+ end;
875+```
876+
877+The **AMsgData** parameter actual type depends on the message processing state and corresponds to :
878+
879+- **IRequestBuffer** on "msBeforeDeserialize" and "msAfterSerialize"
880+- **IFormatterResponse** on "msAfterDeserialize" and "msBeforeSerialize"
881+
882+These types are located in the **server_service_intf** unit. Extensions have to be registered in the extensions registry ( located in the server_service_intf unit ) printed bellow
883+
884+``` pascal
885+ IServiceExtensionRegistry = Interface
886+ ['{68DC78F1-E6CF-4D6B-8473-75288794769C}']
887+ function Find(const AName : string):IServiceExtension;
888+ procedure Register(
889+ const AName : string;
890+ AFactory : IItemFactory
891+ );
892+ end;
893+```
894+
895+In order for an service implementation to use a service extension, it has to register himself to that extension. To that end, the IServiceImplementationFactory interface provides the RegisterExtension method. A complete sample is included in the \samples\http_server sample ( implemented in **\samples\logger_extension.pas** ).
896+
897+## Services meta data
898+
899+Services in the toolkit are organized into ***meta data repositories( see the “services's meta data” below )***. Conceptually a repository corresponds :
900+
901+- at compile time to the pascal unit containing the service definition
902+- at runtime to a name space.
903+
904+The **ws_helper** tool, when parsing the interface definition file, records the meta data of the services contained in the file to a Lazarus resource file. The resource file is then embedded into the generated binder's unit file( see the unit **“initialization”** part ). At runtime the service's recorded meta data are accessible through the interface **IModuleMetadataMngr** defined in the **metadata_repository** unit ( see below ). The **GetModuleMetadataMngr** function defined in the same unit returns an instance of an object supporting that interface.
905+
906+``` pascal
907+ IModuleMetadataMngr = interface
908+ ['{B10ACF6A-A599-45A3-B083-BEEFB810C889}']
909+ function IndexOfName(const ARepName : shortstring):Integer;
910+ function GetCount():Integer;
911+ function GetRepositoryName(const AIndex : Integer):shortstring;
912+ procedure SetRepositoryNameSpace(const ARepName,ANameSpace : shortstring);
913+ function LoadRepositoryName(
914+ const ARepName,ARootAddress : shortstring;
915+ out ARepository : PServiceRepository
916+ ):Integer;
917+ procedure ClearRepository(var ARepository : PServiceRepository);
918+ procedure SetServiceCustomData(
919+ const ARepName : shortstring;
920+ const AServiceName : shortstring;
921+ const ADataName,
922+ AData : string
923+ );
924+ procedure SetOperationCustomData(
925+ const ARepName : shortstring;
926+ const AServiceName : shortstring;
927+ const AOperationName : shortstring;
928+ const ADataName,
929+ AData : string
930+ );
931+ function GetServiceMetadata(const ARepName,AServiceName : shortstring) : PService;
932+ procedure ClearServiceMetadata(var AService : PService);
933+ end;
934+```
935+
936+### Extended Meta data
937+
938+The meta data interface provides a way to add custom data to recorded ones. Services's metadata can be set through **SetServiceCustomData**, operation's metadata be set through the **SetOperationCustomData** method. A repository's extended meta data has to be registered after the service meta data recorded in the resource file have been registered. So for client application the generated proxy unit contains a conditional code fragment to call a registration procedure like showed below for the eBay sample located in the **tests\ebay** folder. The procedure name is obtained from the interface unit name ( the repository's name ) : **Register_%UNIT_NAME%_ServiceMetadata** .
939+
940+``` pascal
941+ initialization
942+ {$i ebay.lrs}
943+
944+ {$IF DECLARED(Register_ebay_ServiceMetadata)}
945+ Register_ebay_ServiceMetadata();
946+ {$ENDIF}
947+ End.
948+```
949+
950+## Headers support
951+
952+### The THeaderBlock class
953+
954+``` pascal
955+ THeaderBlock = class(TBaseComplexRemotable)
956+ public
957+ property Direction : THeaderDirection read FDirection write FDirection;
958+ property Understood : Boolean read FUnderstood write FUnderstood;
959+ published
960+ property mustUnderstand : Integer read FmustUnderstand write SetmustUnderstand
961+ stored HasmustUnderstand;
962+ end;
963+```
964+
965+The **THeaderBlock** showed above ( the private part has been omitted for brevity), located in the **base_service_intf** unit, is the root class all header classes are derived from.. The **Direction** property indicate whether it is an incoming header or an outgoing one. The **mustUnderstand** property define whether the header is a mandatory one.
966+
967+### Defining header class
968+
969+Soap headers are derived from the **THeaderBlock** base class located in the **base_service_intf** unit. They have to be registered in the type registry. Below is reproduced an header example extracted from the “calculator” sample project.
970+
971+``` pascal
972+ TCalcHeader = class(THeaderBlock)
973+ published
974+ property Login : string read FLogin write FLogin;
975+ property Password : string read FPassword write FPassword;
976+ property WantedPrecision : Integer read FWantedPrecision write FWantedPrecision;
977+ end;
978+</synraxhighlight>
979+
980+=== The ICallContext interface ===
981+<syntaxhighlight lang=pascal>
982+ ICallContext = Interface
983+ ['{855EB8E2-0700-45B1-B852-2101023200E0}']
984+ procedure AddObjectToFree(const AObject : TObject);
985+ procedure Clear();
986+ function AddHeader(
987+ const AHeader : THeaderBlock;
988+ const AKeepOwnership : Boolean
989+ ):Integer;
990+ function GetHeaderCount(const ADirections : THeaderDirections):Integer;
991+ function GetHeader(const AIndex : Integer) : THeaderBlock;
992+ procedure ClearHeaders(const ADirection : THeaderDirection);
993+ End;
994+```
995+
996+The **ICallContext** interface defined in the **base_service_intf** unit represents the service call context. The **AddHeader** method allows headers sending while the **GetHeader** method retrieves header in the call context.
997+
998+### Client side headers
999+
1000+An **ICallContext** reference may be obtained from the current service proxy instance simply by querying it for that interface as showed in the code fragment below extracted from the “calculator” client example project.
1001+
1002+``` pascal
1003+ var
1004+ ch : TCalcHeader;
1005+ hdrs : ICallContext;
1006+ begin
1007+ FObj := TCalculator_Proxy.Create('Calculator', edtFormat.Text, edtAddress.Text);
1008+
1009+ ch := TCalcHeader.Create();
1010+ ch.mustUnderstand := 1;
1011+ ch.Login := 'azerty';
1012+ ch.Password := 'qwerty';
1013+ ch.WantedPrecision := 1210;
1014+ hdrs := FObj as ICallContext;
1015+ hdrs.AddHeader(ch,true);
1016+```
1017+
1018+A header may be made mandatory by setting its **mustUnderstand** property to 1 as in the code above.
1019+
1020+### Server side headers
1021+
1022+#### The ICallControl interface
1023+
1024+``` pascal
1025+ ICallControl = interface
1026+ ['{7B4B7192-EE96-4B52-92C7-AE855FBC31E7}']
1027+ procedure SetCallContext(ACallContext : ICallContext);
1028+ function GetCallContext():ICallContext;
1029+ end;
1030+```
1031+
1032+The **ICallControl** interface, located in the **server_service_intf** unit, is used by the toolkit runtime to share the executing call environment with service implementation classes. When the runtime is about to issue a call against a implementation class instance, it queries that instance for ICallControl interface support; If the implementation has ICallControl interface support then the obtained reference is used to set the call context through the **SetCallContext** method. The implementation instance can then access the call context by calling the **GetCallContex** method. The toolkit provides the **TBaseServiceImplementation** class which has support for the ICallControl interface and can be used as a base implementation class. It is the base class used by the **ws_helper** generated skeleton implementation class when invoked with the **-i** command line option. The method printed bellow, extracted from the calculator sample service demonstrates the access to headers for read and write.
1033+
1034+``` pascal
1035+ function TCalculator_ServiceImp.AddInt(
1036+ Const A : Integer;
1037+ Const B : Integer
1038+ ):TBinaryArgsResult;
1039+ var
1040+ hdr : TCalcResultHeader;
1041+ h : TCalcHeader;
1042+ cc : ICallContext;
1043+ Begin
1044+ hdr := TCalcResultHeader.Create();
1045+ cc := GetCallContext();
1046+ if Assigned(cc) and ( cc.GetHeaderCount([hdIn]) > 0 ) and ( cc.GetHeader(0).InheritsFrom(TCalcHeader) ) then begin
1047+ h := cc.GetHeader(0) as TCalcHeader;
1048+ h.Understood := True;
1049+ hdr.Assign(h);
1050+ end;
1051+ hdr.TimeStamp := DateTimeToStr(Now());
1052+ hdr.SessionID := 'testSession';
1053+ cc.AddHeader(hdr,True);
1054+ hdr := nil;
1055+ Result := TBinaryArgsResult.Create();
1056+ Try
1057+ Result.Arg_OP := '+';
1058+ Result.Arg_OpEnum := coAdd;
1059+ Result.Arg_A := A;
1060+ Result.Arg_B := B;
1061+ Result.Arg_R := A + B;
1062+ Result.Comment := 'Doing an + operation';
1063+ Except
1064+ FreeAndNil(Result);
1065+ Raise;
1066+ End;
1067+ End;
1068+```
1069+
1070+## SOAP Specific
1071+
1072+### Binding style
1073+
1074+The binding style is used to indicate whether the service is **RPC** oriented or **Document** oriented.
1075+
1076+#### Client side
1077+
1078+The binding style may be specified in the SOAP protocol string on the creation of a service proxy. The default value for the binding style is **RPC**. Below is printed a sample code that demonstrates the use of Document style.
1079+
1080+``` pascal
1081+ locService := TSampleService_Proxy.Create(
1082+ 'SampleService',
1083+ 'SOAP:Style=Document;EncodingStyle=Litteral',
1084+ 'http:Address=http://127.0.0.1/services/SampleService'
1085+ );
1086+```
1087+
1088+#### Server side
1089+
1090+Currently services created with the toolkit use the **RPC** binding style.
1091+
1092+### Encoding style
1093+
1094+The encoding style indicates the rules used to encode types in XML. Supported values are **Encoded** and **Litteral**.
1095+
1096+#### Client side
1097+
1098+The encoding style may be specified in the SOAP protocol string on the creation of a service proxy. The default value for the encoding style is **Encoded**. The above sample demonstrates the use of **Litteral** style.
1099+
1100+#### Server side
1101+
1102+Currently services created with the toolkit use the **Encoded** encoding style.
1103+
1104+## Provided examples
1105+
1106+The samples are located under the **“tests”** folder.
1107+
1108+### Client side examples ( tested on Windows XP, Ubuntu and MacOS on PowerPC)
1109+
1110+- UserService, samples\http_server, samples\tcp_server, samples\user_client_console, sample\library_server : the client console uses the three client and server protocols (HTTP, TCP, LIBRARY)
1111+- Google sample : It demonstrates use of class and array data types .
1112+- Metadata Browser : This sample demonstrates use of class and array data types and mainly the toolkit metadata service.
1113+- eBay sample, this sample uses OpenSLL which can be found at <http://www.openssl.org> and SYNAPSE ( <http://www.ararat.cz/synapse/> ).
1114+- \samples\delphi\\ : This folder contains Delphi ( compile with Delphi 7) client and server samples. Used protocol : the TCP, HTTP, LIBRARY; Used format : SOAP, XMLRPC and BINARY.
1115+
1116+### Server side examples
1117+
1118+- samples\tcp_server : This is a sample TCP server based on the Synapse components. It uses the UserService.
1119+- samples\http_server : This is a sample HTTP server based on the Indy10 components. It uses the UserService and the toolkit metadata service. It demonstrates the WSDL generation.
1120+- samples\apache_module : Apache module sample, this sample demonstrates the hosting of the toolkit into the Apache HTTP web server. It is based on Sekelsenmat's Apache headers translation. It uses the UserService service and the toolkit metadata service. It demonstrates the WSDL generation.
1121+
1122+## Status
1123+
1124+The toolkit is usable for simple types and for class types. The serialization is designed to allow customization of basic types and class types by implementing classes derived from “TBaseRemotable”. This classes have to be registered in the type registry.
1125+
1126+### Serialization
1127+
1128+The serialization is based on the IFormatterBase interface located in the **base_service_intf** unit.
1129+
1130+The toolkit has three serializers implementations : the SOAP serializer, the XMLRPC serializer and a binary serializer. This serializers has been tested on fpc 2.x and Delphi 7.
1131+
1132+#### *SOAP serializer*
1133+
1134+The SOAP serializer implements SOAP 1.1. It has support for the following pascal types:
1135+
1136+- Available integers :
1137+ - Byte mapped to unsignedByte
1138+ - ShortInt mapped to byte
1139+ - SmallInt mapped to short
1140+ - Word mapped to unsignedShort
1141+ - LongInt mapped to int
1142+ - LongWord mapped to unsignedInt
1143+ - Int64 mapped to long
1144+ - QWord mapped to int
1145+
1146+- String mapped to string
1147+- Boolean mapped to boolean
1148+- Enumerations mapped to their string representation
1149+
1150+- Float types :
1151+ - Single mapped to float
1152+ - Double mapped to double
1153+ - Extended mapped to double
1154+ - Currency mapped to float
1155+
1156+- Object (class instances, not TP ones ) : The toolkit has support for instances of classes derived from TBaseRemotable. TBaseRemotable is the base class used by the formatter interface to allow customization of the serialization. The toolkit provides the TBaseComplexRemotable class which implements serialization for its ( or its descendants ) published properties.
1157+
1158+#### *Binary serializer*
1159+
1160+The Binary serializer is more efficient in time and space compared to the SOAP serializer . It uses big endian to stream data. It has support for the following pascal types:
1161+
1162+- Available integers :
1163+ - Byte
1164+ - ShortInt
1165+ - SmallInt
1166+ - Word
1167+ - LongInt
1168+ - LongWord
1169+ - Int64
1170+ - QWord
1171+
1172+- String
1173+- Boolean
1174+- Enumerations
1175+
1176+- Float types :
1177+ - Single
1178+ - Double
1179+ - Extended
1180+ - Currency
1181+
1182+- Object (class instances, not TP ones ) :The toolkit has support for instances of classes derived from **TBaseRemotable**. TBaseRemotable is the base class used by the formatter interface to allow customization of the serialization. The toolkit provides the TBaseComplexRemotable class which implements serialization for its ( or its descendants ) published properties.
1183+
1184+#### *Class type serialization*
1185+
1186+The toolkit has support for instances of classes derived from **TBaseRemotable**. TBaseRemotable is the abstract base class used by the formatter interface to allow customization of the serialization. The toolkit provides the TBaseComplexRemotable class which implements serialization for its descendants classes published properties. It also provides TBaseObjectArrayRemotable class for serialization of array of TBaseRemotable descendant classes.
1187+
1188+##### The root **“TBaseRemotable”** class
1189+
1190+``` pascal
1191+ TBaseRemotable = class(TPersistent)
1192+ Public
1193+ constructor Create();virtual;
1194+ class procedure Save(
1195+ AObject : TBaseRemotable;
1196+ AStore : IFormatterBase;
1197+ Const AName : String;
1198+ Const ATypeInfo : PTypeInfo
1199+ );virtual;abstract;
1200+ class procedure Load(
1201+ Var AObject : TObject;
1202+ AStore : IFormatterBase;
1203+ var AName : String;
1204+ const ATypeInfo : PTypeInfo
1205+ );virtual;abstract;
1206+ End;
1207+```
1208+
1209+**TBaseRemotable** is the abstract base class used by the formatter interface to allow customization of the serialization. This class defines a **virtual constructor** and mainly two(2) virtual abstract class methods :
1210+
1211+- **Save** : this method is called when the toolkit needs to serialize the **AObject** parameter.
1212+- **Load**: this method is called when the toolkit needs to un-serialize to the **AObject** parameter.
1213+
1214+##### The “TBaseComplexRemotable” serialization
1215+
1216+``` pascal
1217+ TBaseComplexRemotable = class(TAbstractComplexRemotable)
1218+ public
1219+ class procedure Save(
1220+ AObject : TBaseRemotable;
1221+ AStore : IFormatterBase;
1222+ const AName : string;
1223+ const ATypeInfo : PTypeInfo
1224+ );override;
1225+ class procedure Load(
1226+ var AObject : TObject;
1227+ AStore : IFormatterBase;
1228+ var AName : string;
1229+ const ATypeInfo : PTypeInfo
1230+ );override;
1231+ class procedure RegisterAttributeProperty(const AProperty : shortstring);virtual;
1232+ class procedure RegisterAttributeProperties(const APropertList : array of shortstring);virtual;
1233+ class function IsAttributeProperty(const AProperty : shortstring):Boolean;
1234+ procedure Assign(Source: TPersistent); override;
1235+ end;
1236+```
1237+
1238+**TBaseComplexRemotable** implements serialization for its descendants classes published properties. The serialization is based on runtime type information (RTTI) and can be customized to:
1239+
1240+- ignore always some published properties.
1241+- ignore conditionally some published properties.
1242+
1243+The following class shows a the serialization's customization sample.
1244+
1245+``` pascal
1246+ TSampleClass = class(TBaseComplexRemotable)
1247+ private
1248+ FProp_Always: Integer;
1249+ FProp_Never: Integer;
1250+ FProp_Optional: Integer;
1251+ function GetStoredProp_Optional: boolean;
1252+ published
1253+ //This property will always be serialized
1254+ property Prop_Always : Integer read FProp_Always write FProp_Always;
1255+ //This property will never be serialized
1256+ property Prop_Never : Integer read FProp_Never write FProp_Never stored False;
1257+ //This property will be serialized if "Self.GetStoredProp_Optional() = True"
1258+ property Prop_Optional : Integer read FProp_Optional write FProp_Optional stored GetStoredProp_Optional;
1259+ End;
1260+```
1261+
1262+- Attribute properties
1263+
1264+TBaseComplexRemotable allows properties serialization as attributes. Theses properties have to be registered as such with the RegisterAttributeProperty class method or RegisterAttributeProperties one.
1265+
1266+##### TBaseComplexRemotable
1267+
1268+**TBaseComplexSimpleContentRemotable** provides implementation for the “XML Schema” complex types which extend simple types with attributes. The following example illustrates this :
1269+
1270+``` xml
1271+ <xs:complexType name="DecimalWithUnits">
1272+ <xs:simpleContent>
1273+ <xs:extension base="xs:decimal">
1274+ <xs:attribute name="Units" type="xs:string"
1275+ use="required"/>
1276+ </xs:extension>
1277+ </xs:simpleContent>
1278+ </xs:complexType>
1279+```
1280+
1281+This type will be translate by ws_helper to Pascal as
1282+
1283+``` pascal
1284+ DecimalWithUnits = class(TComplexFloatExtendedContentRemotable)
1285+ private
1286+ FUnits : string;
1287+ published
1288+ property Units : string read FUnits write FUnits;
1289+ end;
1290+```
1291+
1292+using the predefined types ( in base_service_intf.pas )
1293+
1294+``` pascal
1295+ TBaseComplexSimpleContentRemotable =
1296+ class(TAbstractComplexRemotable)
1297+ protected
1298+ class procedure SaveValue(
1299+ AObject : TBaseRemotable;
1300+ AStore : IformatterBase
1301+ );virtual;abstract;
1302+ class procedure LoadValue(
1303+ var AObject : TObject;
1304+ AStore : IformatterBase
1305+ );virtual;abstract;
1306+ public
1307+ class procedure Save(
1308+ AObject : TBaseRemotable;
1309+ AStore : IFormatterBase;
1310+ const AName : string;
1311+ const ATypeInfo : PTypeInfo
1312+ );override;
1313+ class procedure Load(
1314+ var AObject : TObject;
1315+ AStore : IFormatterBase;
1316+ var AName : string;
1317+ const ATypeInfo : PTypeInfo
1318+ );override;
1319+ end;
1320+
1321+ TComplexFloatExtendedContentRemotable =
1322+ class(TBaseComplexSimpleContentRemotable)
1323+ private
1324+ FValue: Extended;
1325+ protected
1326+ class procedure SaveValue(
1327+ AObject : TBaseRemotable;
1328+ AStore : IformatterBase
1329+ );override;
1330+ class procedure LoadValue(
1331+ var AObject : TObject;
1332+ AStore : IformatterBase
1333+ );override;
1334+ public
1335+ property Value : Extended read FValue write FValue;
1336+ end;
1337+```
1338+
1339+An instance of this type looks like the one below. Every attribute must be registered using the **RegisterAttributeProperty()** method. The toolkit provides class for Pascal basic types( TComplexInt8UContentRemotable, TComplexInt8SContentRemotable, TComplexInt16SContentRemotable, ...).
1340+
1341+``` xml
1342+ <example Units = "meter">
1343+ 12.10
1344+ </example>
1345+```
1346+
1347+##### Provided array implementations
1348+
1349+The toolkit provides array implementation for basic types ( in the **base_service_intf** unit ) listed bellow. The implementations are based on the serialization's customization.
1350+
1351+- Available integers :
1352+ - Byte **TArrayOfInt8URemotable**
1353+ - ShortInt **TArrayOfInt8SRemotable**
1354+ - SmallInt **TArrayOfInt16SRemotable**
1355+ - Word **TArrayOfInt16URemotable**
1356+ - LongInt **TArrayOfInt32SRemotable**
1357+ - LongWord **TArrayOfInt32URemotable**
1358+ - Int64 **TArrayOfInt64SRemotable**
1359+ - Qword **TArrayOfInt64URemotable**
1360+- String **TarrayOfStringRemotable**( AnsiString )
1361+- Boolean **TArrayOfBooleanRemotable**
1362+- Float types :
1363+ - Single **TArrayOfFloatSingleRemotable**
1364+ - Double **TArrayOfFloatDoubleRemotable**
1365+ - Extended **TArrayOfFloatExtendedRemotable**
1366+ - Currency **TArrayOfFloatCurrencyRemotable**
1367+
1368+The toolkit array's implementation support “embedded” array serialization. This type of array occurs typically with types like the following one ( the "ResponseGroup" may be repeated ):
1369+
1370+``` xml
1371+ <xs:complexType name="CustomerContentSearchRequest">
1372+ <xs:sequence>
1373+ <xs:element name="CustomerPage" type="xs:positiveInteger"
1374+ minOccurs="0"/>
1375+ <xs:element name="Email" type="xs:string" minOccurs="0"/>
1376+ <xs:element name="Name" type="xs:string" minOccurs="0"/>
1377+ <xs:element name="ResponseGroup" type="xs:string"
1378+ minOccurs="0" maxOccurs="unbounded"/>
1379+ </xs:sequence>
1380+ </xs:complexType>
1381+```
1382+
1383+which could be instantiated as
1384+
1385+``` xml
1386+ <search>
1387+ <CustomerPage> 1 </CustomerPage>
1388+ <Name>Sample name</Name>
1389+ <ResponseGroup>Group 1</ResponseGroup>
1390+ <ResponseGroup>Group 2</ResponseGroup>
1391+ <ResponseGroup>Group 3</ResponseGroup>
1392+ </search>
1393+```
1394+
1395+This type will be translate to Pascal by ws_helper as (the private and protected parts are omitted to be short)
1396+
1397+``` pascal
1398+(...)
1399+ CustomerContentSearchRequest_ResponseGroupArray =
1400+ class(TBaseSimpleTypeArrayRemotable)
1401+ public
1402+ class function GetItemTypeInfo():PTypeInfo;override;
1403+ procedure SetLength(const ANewSize : Integer);override;
1404+ property Item[AIndex:Integer] : string
1405+ read GetItem write SetItem; default;
1406+ end;
1407+
1408+ CustomerContentSearchRequest = class(TBaseComplexRemotable)
1409+ published
1410+ property CustomerPage : positiveInteger
1411+ read FCustomerPage
1412+ write FCustomerPage stored HasCustomerPage;
1413+ property Email : string
1414+ read FEmail
1415+ write FEmail
1416+ stored HasEmail;
1417+ property Name : string read FName write FName stored HasName;
1418+ property ResponseGroup :
1419+ CustomerContentSearchRequest_ResponseGroupArray
1420+ read FResponseGroup
1421+ write FResponseGroup;
1422+ end;
1423+
1424+implementation
1425+(...)
1426+ GetTypeRegistry().ItemByTypeInfo[
1427+ TypeInfo(CustomerContentSearchRequest_ResponseGroupArray)]
1428+ .RegisterExternalPropertyName(sARRAY_STYLE,sEmbedded);
1429+(...)
1430+```
1431+
1432+The last instruction set the array style to “Embedded” and so the SOAP formatter will serialize the array accordingly.
1433+
1434+#### *Test cases*
1435+
1436+- The toolkit uses FPCUnit for test cases. The test project is located in the \tests\test_suite folder.
1437+- The Delphi tests suite is based on Dunit and is located in the \tests\test_suite\delphi folder.
1438+
1439+## TODO
1440+
1441+### TODO Common
1442+
1443+- Simple type support in headers
1444+- Header support for the binary format
1445+- True Attribute serialization support for the binary format
1446+
1447+### TODO Client-Side
1448+
1449+- ~~Basic array support~~ for SOAP
1450+- ~~Basic array support~~ for Binary format
1451+- ~~XML-RPC formatter~~
1452+- More documentation and samples !
1453+ - ~~eBay basic client~~ : demonstrates the **GetPopularKeywords** operation call
1454+ - ~~"Amazon E-Commerce Service" sample~~
1455+- ~~WSDL to pascal compiler~~
1456+- ~~Enhance the pascal parser~~ : the toolkit now uses the fcl-passrc
1457+- Client side services extensions
1458+
1459+### TODO Server-Side
1460+
1461+Extend the toolkit to Server side for :
1462+
1463+- ~~SOAP~~
1464+- ~~Binary serialization~~
1465+- ~~Bytes ordering in binary serialization : alaways use big-endian~~
1466+- ~~XML-RPC~~
1467+- ~~TCP transport~~ ( first implementation).
1468+- ~~WSDL generation~~
1469+- More documentation and samples !
1470+- ~~Apache support~~ : services as Apache modules using Sekelsenmat 's \[\[:fpc:FPC_and_Apache_Modules \| Apache headers translation
1471+
1472+\]\]
1473+
1474+- - See the **apache_module** sample located in the ***tests\apache_module*** folder
1475+- Classes inheritance generation in WSDL
1476+
1477+## Licence
1478+
1479+- The support units are provided under modified LGPL
1480+- ws_helper sources are provided under GPL 2 ( or later version )
1481+
1482+## Download & NewsGroup
1483+
1484+- The lastest version can be found at <http://inoussa12.googlepages.com/webservicetoolkitforfpc%26lazarus> and from [Lazarus-CCR sourceforge site](http://sourceforge.net/project/showfiles.php?group_id=92177&package_id=196167).
1485+- The developement sources can be obtained by svn at <https://lazarus-ccr.svn.sourceforge.net/svnroot/lazarus-ccr/wst/trunk>
1486+
1487+The "Web Service Toolkit" now has a newsgroup hosted at <news://news.dxmachine.com/public.wst>
1488+
1489+## Changes Log
1490+
1491+### Version 0.5
1492+
1493+- Lazarus IDE WSDL importer wizard
1494+- WSDL GUI editor ( Type library editor )
1495+- Listener design : easy server development
1496+ - Indy HTTP server listener
1497+ - Indy TCP server listener
1498+ - Synapse TCP server listener
1499+- XMLRPC support : client and server
1500+- Switch from the custom pascal parser to fcl-passrc
1501+- Server side : implementation objects pooling
1502+- Better Delphi support
1503+ - SOAP XMLRPC and binary format support
1504+ - DUnit test suite
1505+- WST has been tested on
1506+ - Windows
1507+ - Linux
1508+ - MacOSX PowerPC
1509+- Better WSDL parsing
1510+- Services configuration in external file
1511+- TStringBufferRemotable ( reading a node's raw buffer )
1512+- Bugs fixes
1513+
1514+### Version 0.4
1515+
1516+- WSDL to Pascal translation support in "ws_helper"
1517+- new TCP transport implementation ( using synapse library ) in synapse_tcp_protocol.pas
1518+- new library protocol implementation in library_protocol.pas
1519+- TCP server implementation ( using synapse library ) in synapse_tcp_server.pas
1520+- Delphi : first binary format support
1521+- Embedded array support
1522+- Object Pascal reserved words can now be used as service methods's name, enumeration, ... ( see TTypeRegistryItem.RegisterExternalPropertyName() )
1523+- The toolkit can now be used with FPC without Lazarus
1524+- "Amazon E-Commerce Service" sample
1525+- Bugs Fixes.
1526+
1527+### Version 0.3.1 ( 21 August 2006 )
1528+
1529+- Apache Web Server support : services hosting as Apache's module.
1530+ - See the **apache_module** sample located in the ***tests\apache_module*** folder.
1531+- Important : In the connection string the address token was mis-spelled as **adress** (one letter "d" instead of two), it has been corrected to **address**.
1532+- Bugs Fixes.
1533+
1534+### Version 0.3 ( 5 August 2006 )
1535+
1536+- Header support ( client and server side )
1537+- Server side service extensions
1538+- Attribute serialization
1539+- New transport implementation : Synapse HTTP client support
1540+- Address per operation support ( client side )
1541+- Extended meta data
1542+- Bug Fixes
1543+
1544+### Version 0.2.3.2 ( 5 July 2006 )
1545+
1546+- ICS and Indy HTTP Proxy "user" and "passeword" support.
1547+
1548+### Version 0.2.3 ( 4 July 2006 )
1549+
1550+- WSDL generation
1551+- Metadata service
1552+- Metadata Browser sample
1553+- HTTP server sample
1554+- Pascal basic types array implementation
1555+- The ws_helper's parser now supports:
1556+ - {} comment style in the input file
1557+ - service interfaces may have GUID
1558+- more test cases
1559+- bug fix
1560+
1561+### Version 0.2.2 ( 7 June 2006 )
1562+
1563+- All pascal basic types are supported by the **SOAP serializer** and the **Binary serializer** ( Available integers, available floats, string, boolean, Enumerations, class intances )
1564+- Array support for Binary serializer
1565+- FPCUnit test cases
1566+ - SOAP serializer ( basic types and classes instances )
1567+ - Binary serializer ( basic types and classes instances )
1568+- All interfaces now have GUID
1569+
1570+## Author
1571+
1572+Inoussa OUEDRAOGO, <http://inoussa12.googlepages.com/>
1573+
1574+---
1575+*From the Free Pascal wiki, page "Web Service Toolkit/fr", as it stood on 2020-03-04 after a change by Trev, out of the wiki's dump of 2024-05-26. Copyright stays with the author who wrote it, according to the old wiki's [[Licensing]] page. If you have concerns about this material, [message the admin](/wiki-contact).*

Back to history