Sign in Join
Wiki copytemporary

Web Service Toolkit/pt: what changed

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

OldNewLine
11"Web Service Toolkit” é um pacote de serviços Web para FPC e Lazarus. “Web Service Toolkit” significa facilidade de criação e uso de serviços Web pelos usuários do FPC e do Lazarus.
22
33## A Aplicação-Cliente ( uso do serviço )
44
55### Visão Geral
66
77O “Web Service Toolkit” é feito de duas partes, uma ferramenta de linha de comando “ws_helper” e uma coleção de unidades de suporte. Dado um arquivo de definição de interface (um arquivo WSDL ou um arquivo Pascal descrevendo o serviço Web), “ws_helper” vai criar uma unidade FPC contendo um proxy implementando esta inteface. Em tempo de execução, quando uma chamada ao serviço Web for executada, a ação do proxy é para
88
99- Monitoramento dos parâmetros da chamada
1010- fazer a chamada do serviço-alvo
1111- receber o retorno da chamada e desmonitoramento dos parâmetros da saída para o chamador.
1212
1313Atrás da cena, o proxy cuidará dos detalhes do SOAP plumbing.
1414
1515### Exemplo
1616
1717Nós vamos usar o “Amazon E-Commerce Service” disponível livremente (você vai precisar criar uma conta, é free) para uso pessoal neste endereço [1](http://www.amazon.com/gp/browse.html?node=3435361). Para usar este serviço, temos que baixar a interface WSDL (Web Services Description Language) e traduzi-la para a linguagem Pascal. O programa ws_helper manejará isto para nós. Para apresentar suas capacidades, estão abaixo os argumentos de linha de comando que ele suporta.
1818
1919 ws_helper [-uMODE] [-p] [-b] [-i] [-oPATH] inputFilename
2020 -u MODE Generate the pascal translation of the WSDL input file
2121 MODE value may be U for used types or A for all types
2222 -p Generate service proxy
2323 -b Generate service binder
2424 -i Generate service minimal implementation
2525 -o PATH Relative output directory
2626 -a PATH Absolute output directory
2727
2828Para traduzir o arquivoo WSDL baixado do website do “Amazon E-Commerce Service”, execute o seguinte da linha de comando:
2929
3030 ..\..\ws_helper\ws_helper.exe -uA -p -o. AWSECommerceService.wsdl
3131 ws_helper, Web Service Toolkit 0.4 Copyright (c) 2006, 2007 by Inoussa OUEDRAOGO
3232
3333 Parsing the file : AWSECommerceService.wsdl
3434 Interface file generation...
3535 Proxy file generation...
3636 Metadata file generation...
3737 File "AWSECommerceService.wsdl" parsed succesfully.
3838
3939Vão-se produzir dois arquivos:
4040
4141- AWSECommerceService.pas, o arquivo de definição do serviço
4242- AWSECommerceService_proxy.pas, este arquivo contém um proxy que implementa a interface do serviço definida no primeiro arquivo.
4343
4444Abaixo está um extrato dos dois arquivos:
4545
4646``` pascal
4747unit AWSECommerceService;
4848{$IFDEF FPC} {$mode objfpc}{$H+} {$ENDIF}
4949interface
5050
5151uses SysUtils, Classes, TypInfo, base_service_intf, service_intf;
5252
5353const
5454 sNAME_SPACE = 'http://webservices.amazon.com/AWSECommerceService/2007-04-04';
5555 sUNIT_NAME = 'AWSECommerceService';
5656
5757type
5858
5959 HelpRequest = class;
6060 Help_RequestArray = class;
6161
6262(...)
6363
6464 AWSECommerceServicePortType = interface(IInvokable)
6565 ['{305A7E48-DD92-4C20-B699-4F2B47C93342}']
6666 function Help(
6767 Const HelpParam : Help_Type
6868 ):HelpResponse_Type;
6969 function ItemSearch(
7070 Const ItemSearchParam : ItemSearch_Type
7171 ):ItemSearchResponse_Type;
7272 function ItemLookup(
7373 Const ItemLookupParam : ItemLookup_Type
7474 ):ItemLookupResponse_Type;
7575 (...)
7676 end;
7777
7878 procedure Register_AWSECommerceService_ServiceMetadata();
7979```
8080
8181``` pascal
8282Unit AWSECommerceService_proxy;
8383{$IFDEF FPC} {$mode objfpc}{$H+} {$ENDIF}
8484Interface
8585
8686Uses SysUtils, Classes, TypInfo, base_service_intf, service_intf, AWSECommerceService;
8787
8888Type
8989
9090 TAWSECommerceServicePortType_Proxy=class(TBaseProxy,AWSECommerceServicePortType)
9191 Protected
9292 class function GetServiceType() : PTypeInfo;override;
9393 function Help(
9494 Const HelpParam : Help_Type
9595 ):HelpResponse_Type;
9696 function ItemSearch(
9797 Const ItemSearchParam : ItemSearch_Type
9898 ):ItemSearchResponse_Type;
9999 function ItemLookup(
100100 Const ItemLookupParam : ItemLookup_Type
101101 ):ItemLookupResponse_Type;
102102 (...)
103103 End;
104104
105105 Function wst_CreateInstance_AWSECommerceServicePortType(
106106 const AFormat : string = 'SOAP:';
107107 const ATransport : string = 'HTTP:'
108108 ):AWSECommerceServicePortType;
109109
110110Implementation
111111uses wst_resources_imp, metadata_repository;
112112
113113Function wst_CreateInstance_AWSECommerceServicePortType(
114114 const AFormat : string;
115115 const ATransport : string
116116):AWSECommerceServicePortType;
117117Begin
118118 Result := TAWSECommerceServicePortType_Proxy.Create(
119119 'AWSECommerceServicePortType',
120120 AFormat +
121121 GetServiceDefaultFormatProperties(TypeInfo(AWSECommerceServicePortType)),
122122 ATransport + 'address=' + GetServiceDefaultAddress(TypeInfo(AWSECommerceServicePortType))
123123 );
124124End;
125125
126126function TAWSECommerceServicePortType_Proxy.ItemSearch(
127127 Const ItemSearchParam : ItemSearch_Type
128128):ItemSearchResponse_Type;
129129Var
130130 locSerializer : IFormatterClient;
131131 strPrmName : string;
132132Begin
133133 locSerializer := GetSerializer();
134134 Try
135135 locSerializer.BeginCall('ItemSearch', GetTarget(),(Self as ICallContext));
136136 locSerializer.Put('ItemSearch', TypeInfo(ItemSearch_Type), ItemSearchParam);
137137 locSerializer.EndCall();
138138
139139 MakeCall();
140140
141141 locSerializer.BeginCallRead((Self as ICallContext));
142142 TObject(Result) := Nil;
143143 strPrmName := 'ItemSearchResponse';
144144 locSerializer.Get(TypeInfo(ItemSearchResponse_Type), strPrmName, Result);
145145
146146 Finally
147147 locSerializer.Clear();
148148 End;
149149End;
150150(...)
151151```
152152
153153Nós agora podemos construir um programa simples para o serviço. A biblioteca Synapse é requerida para compilar o programa como ele é usado para a comunicação HTTP. Esta biblioteca pode ser baixada livre de taxa neste endereço: [2](http://synapse.ararat.cz/). A biblioteca Indy [3](http://www.indyproject.org/Sockets/fpc/index.en.html) ou a biblioteca ICS [4](http://www.overbyte.be/frame_index.html) também podem ser usadas.
154154
155155``` pascal
156156program amazon_sample;
157157{$mode objfpc}{$H+}
158158uses
159159 Classes, SysUtils, soap_formatter, synapse_http_protocol,
160160 metadata_repository, AWSECommerceService, AWSECommerceService_proxy;
161161
162162const sACCES_ID = <Your AccesID here>;
163163
164164function ReadEntry(const APromp : string):string ;
165165begin
166166 Result := '';
167167 Write(APromp);
168168 while True do begin
169169 ReadLn(Result);
170170 Result := Trim(Result);
171171 if ( Length(Result) > 0 ) then
172172 Break;
173173 end;
174174end;
175175
176176var
177177 locService : AWSECommerceServicePortType;
178178 rqst : ItemSearch_Type;
179179 rsps : ItemSearchResponse_Type;
180180 rspsItem : Items_Type;
181181 i, j, k : Integer;
182182 itm : Item_Type;
183183begin
184184 SYNAPSE_RegisterHTTP_Transport();
185185 WriteLn('Web Services Toolkit Amazon sample');
186186 WriteLn('This sample demonstrates the "ItemSearch" method of the Amazon web service');
187187 WriteLn();
188188 rqst := ItemSearch_Type.Create();
189189 try
190190 locService := wst_CreateInstance_AWSECommerceServicePortType();
191191 rqst.AWSAccessKeyId := sACCES_ID;
192192 while True do begin
193193 rqst.Request.SetLength(1);
194194 rqst.Request[0].SearchIndex := ReadEntry('Enter the Search Index : ');
195195 rqst.Request[0].Availability := Available;
196196 rqst.Request[0].Count := 10;
197197 rqst.Request[0].MerchantId := 'Amazon';
198198 rqst.Request[0].ItemPage := 1;
199199 rqst.Request[0].Keywords := ReadEntry('Enter the Keywords : ');
200200 rsps := locService.ItemSearch(rqst);
201201 if ( rsps.OperationRequest.Errors.Length > 0 ) then begin
202202 WriteLn(Format('Errors ( %d ) : ',[rsps.OperationRequest.Errors.Length]));
203203 for i := 0 to Pred(rsps.OperationRequest.Errors.Length) do begin
204204 WriteLn(Format(' Error[%d] :',[i]));
205205 WriteLn(' ' + rsps.OperationRequest.Errors[i].Code);
206206 WriteLn(' ' + rsps.OperationRequest.Errors[i].Message);
207207 end;
208208 end else begin
209209 WriteLn(Format('Response ( %d ) : ',[rsps.Items.Length]));
210210 if Assigned(rsps) then begin
211211 for i := 0 to Pred(rsps.Items.Length) do begin
212212 rspsItem := rsps.Items[i];
213213 WriteLn(' TotalPages :' + IntToStr(rspsItem.TotalPages));
214214 WriteLn(' TotalResults :' + IntToStr(rspsItem.TotalResults));
215215 WriteLn(' Items :' + IntToStr(rspsItem._Item.Length));
216216 WriteLn('');
217217 for j := 0 to Pred(rspsItem._Item.Length) do begin
218218 itm := rspsItem._Item[j];;
219219 WriteLn(' ASIN :' + itm.ASIN);
220220 WriteLn(' DetailPageURL :' + itm.DetailPageURL);
221221 if Assigned(itm.ItemAttributes) then begin
222222 WriteLn(' Title :' + itm.ItemAttributes.Title);
223223 for k := 0 to Pred(itm.ItemAttributes.Author.Length) do begin
224224 WriteLn(' Author[ ' + IntToStr(k) + ' ] ' + itm.ItemAttributes.Author.Item[k]);
225225 end;
226226 WriteLn(' Manufacturer :' + itm.ItemAttributes.Manufacturer);
227227 WriteLn(' ProductGroup :' + itm.ItemAttributes.ProductGroup);
228228 end;
229229 WriteLn('');
230230 end;
231231 end;
232232 end else begin
233233 WriteLn('Unexpected service response : Invalid response');
234234 end;
235235 end;
236236 WriteLn();
237237 WriteLn();
238238 if ( UpperCase(ReadEntry('Continue ( Y/N ) :'))[1] <> 'Y' ) then
239239 Break;
240240 end;
241241 finally
242242 FreeAndNil(rqst);
243243 FreeAndNil(rsps);
244244 end;
245245 ReadLn;
246246end.
247247```
248248
249249As unidades base_service_intf, service_intf, soap_formatter, synapse_http_protocol, wst_resources_imp e metadata_repository são fornecidas com o toolkit. Abaixo está o resultado da execução da sessão de busca de “Freepascal” no índice de busca “All” (o serviço diferencia maiúscula/minúscula).
250250
251251 Web Services Toolkit Amazon sample
252252 This sample demonstrates the "ItemSearch" method of the Amazon web service
253253
254254 Enter the Search Index : All
255255 Enter the Keywords : Freepascal
256256 Response ( 1 ) :
257257 TotalPages :1
258258 TotalResults :9
259259 Items :9
260260
261261 ASIN :0470088702
262262 DetailPageURL : http://www.amazon.com/gp/redirect.html%3FASIN=0470088702%26tag=ws%26lcode=sp1%26cID=2025%26ccmID=165953%26location=/o/ASIN/0470088702%253FSubscriptionId=0W3H25JMMGBNBXSTQN82
263263 Title :Beginning Programming For Dummies (Beginning Programming f
264264 or Dummies)
265265 Author[ 0 ] Wallace Wang
266266 Manufacturer :For Dummies
267267 ProductGroup :Book
268268
269269 ASIN :0471375233
270270 DetailPageURL : http://www.amazon.com/gp/redirect.html%3FASIN=0471375233%26tag=ws%26lcode=sp1%26cID=2025%26ccmID=165953%26location=/o/ASIN/0471375233%253FSubscriptionId=0W3H25JMMGBNBXSTQN82
271271 Title :Assembly Language Step-by-step: Programming with DOS and Linux (with CD-ROM)
272272 Author[ 0 ] Jeff Duntemann
273273 Manufacturer :Wiley
274274 ProductGroup :Book
275275 (...)
276276
277277Isto encontra uma página contendo nove ítens. A função wst_CreateInstance_AWSECommerceServicePortType(), localizada no arquivo AWSECommerceService.pas cria uma instância do proxy baseada na informação do serviço contida no arquivo WSDL.
278278
279279``` pascal
280280Function wst_CreateInstance_AWSECommerceServicePortType(
281281 const AFormat : string;
282282 const ATransport : string
283283):AWSECommerceServicePortType;
284284Begin
285285 Result := TAWSECommerceServicePortType_Proxy.Create(
286286 'AWSECommerceServicePortType',
287287 Aformat + GetServiceDefaultFormatProperties(TypeInfo(AWSECommerceServicePortType)),
288288 ATransport + 'address=' + GetServiceDefaultAddress(TypeInfo(AWSECommerceServicePortType))
289289 );
290290End;
291291```
292292
293-`Os fontes completos deste exemplo são entregues com o toolkit.`
293+```text
294+Os fontes completos deste exemplo são entregues com o toolkit.
295+```
294296
295297### Parâmetros de Connexão
296298
297299O formato geral é:
298300
299301 protocol:paramName=paramValue(;paramName=paramValue)*
300302
301303#### Parâmetros do Proxy HTTP
302304
303305Para HTTP os parâmetros suportados são:
304306
305307- Address **( required for a service supporting a unique address )**
306308- ProxyServer
307309- ProxyPort
308310- ProxyUsername
309311- ProxyPassword
310312
311313HTTP Connection through proxy are supported. Below is an example address string.
312314
313315``` pascal
314316 const
315317 sADDRESS = 'http:address=http://webservices.amazon.com/AWSECommerceService/2007-04-04'+
316318 ';ProxyServer=197.150.10.10;ProxyPort=9881'+
317319 ';ProxyUsername=inoussa;ProxyPassword=wst';
318320```
319321
320322The toolkit has two TCP implementations based on Synapse ( synapse_tcp_protocol.pas ) and ICS ( ics_tcp_protocol.pas ).
321323
322324#### Parâmetros da Conexão TCP
323325
324326Os parâmetros de TCP suportados são:
325327
326328- address ( required for a service supporting a unique address )
327329- Port
328330- target( the target service )
329331
330332Abaixo está um exemplo de uma string de endereço.
331333
332334``` pascal
333335 Const
334336 sADDRESS = 'TCP:Address=10.0.0.3;Port=1234;target=UserService';
335337```
336338
337339The toolkit has two TCP implementations based on Synapse ( synapse_tcp_protocol.pas ) and ICS ( ics_tcp_protocol.pas ).
338340
339341#### Parâmetros de Conexão LIBRARY ( LIB )
340342
341343A idéia por trás deste protocolo é poder hospedar serviços em bibliotecas dinâmicas (DLL/DSO). Isto pode ser visto como um framework de plug-in em que plug-ins (serviços) são fornecidos por bibliotecas dinâmicas. Os parâmetros para LIB suportados são:
342344
343345- FileName ( the DLL/SO filename )
344346- target( the target service )
345347
346348Abaixo um exemplo de uma string de endereço.
347349
348350``` pascal
349351 Const
350352 sADDRESS = 'LIB:FileName=..\library_server\lib_server.dll;target=UserService';
351353```
352354
353355The toolkit has one LIB implementation ( library_protocol.pas ).
354356
355357***As pastas sample contêm 3 projetos, user_client_console, tcp_server e library_server que demonstra os protocolos TCP e LIBRARY.***
356358
357359#### Serviço Multi-Endereço ( Endereço por operação )
358360
359361Certos serviços (como os serviços do eBay SOAP) usam um endereço por operação. O toolkit usa meta-dados estendidos (veja o capítulo sobre serviços de meta-dados abaixo) para configurar endereço de operação. O sample SOAP do eBay localizado na pasta test\eBay demonstra a configuração do endereço da operação.
360362
361363## Server Side ( service creation )
362364
363365### Overview
364366
365367Web Service Toolkit contains a server side framework for service creation. Key features are:
366368
367369- Service definition( interface ) is separated from implementation,
368370- Interface and implementations are not bound to message protocol,
369371- WSDL generation,
370372- Support for SOAP 1.1 and a binary protocol,
371373- The framework is not bound to a transport protocol.
372374- Easy to add support for application servers
373375
374376### Example
375377
376378In order to create a service, we have to :
377379
378380- define its interface,
379381- provide an implementation and register that one for the service,
380382- provide a binder that will route calls targeting the service to the implementation and register that one,
381383- host the service into an application server( TCP server, HTTP Server, LIBRARY server, ... ).
382384
383385#### Defining the service Interface
384386
385387We will use the interface defined below for our sample. The complete projects of the example is located in the folder “samples”.
386388
387389``` pascal
388390unit user_service_intf;
389391{$IFDEF FPC} {$mode objfpc}{$H+} {$ENDIF}
390392interface
391393
392394uses SysUtils, Classes, TypInfo, base_service_intf, service_intf;
393395
394396const
395397 sNAME_SPACE = 'urn:UserService';
396398 sUNIT_NAME = 'user_service_intf';
397399
398400type
399401
400402 TUser = class;
401403 TUserArray = class;
402404
403405 TUserCategory = (
404406 Normal
405407 ,Admin
406408 );
407409
408410 TUser = class(TBaseComplexRemotable)
409411 private
410412 FCategory : TUserCategory;
411413 FUserName : string;
412414 FeMail : string;
413415 FPreferences : string;
414416 published
415417 property Category : TUserCategory read FCategory write FCategory;
416418 property UserName : string read FUserName write FUserName;
417419 property eMail : string read FeMail write FeMail;
418420 property Preferences : string read FPreferences write FPreferences;
419421 end;
420422
421423 TUserArray = class(TBaseObjectArrayRemotable)
422424 private
423425 function GetItem(AIndex: Integer): TUser;
424426 public
425427 class function GetItemClass():TBaseRemotableClass;override;
426428 property Item[AIndex:Integer] : TUser Read GetItem;Default;
427429 end;
428430
429431 UserService = interface(IInvokable)
430432 ['{CA6F6192-C3DE-4D9C-B3DF-E616376A0DC9}']
431433 function GetList():TUserArray;
432434 procedure Add(
433435 Const AUser : TUser
434436 );
435437 procedure Update(
436438 Const AUser : TUser
437439 );
438440 function Find(
439441 Const AName : string
440442 ):TUser;
441443 function Delete(
442444 Const AName : string
443445 ):boolean;
444446 end;
445447(...)
446448```
447449
448450#### Providing an implementation for the service
449451
450452“ws_helper” has options to generate proxy file, basic implementation skeleton file and a binder file ( see the following listing).
451453
452454 ws_helper, Web Service Toolkit 0.4 Copyright (c) 2006, 2007 by Inoussa OUEDRAOGO
453455 ws_helper [-uMODE] [-p] [-b] [-i] [-oPATH] inputFilename
454456 -u MODE Generate the pascal translation of the WSDL input file
455457 MODE value may be U for used types or A for all types
456458 -p Generate service proxy
457459 -b Generate service binder
458460 -i Generate service minimal implementation
459461 -o PATH Relative output directory
460462 -a PATH Absolute output directory
461463
462464Executing “ws_helper” with the -i and -b options as above will produce two files : user_service_intf_imp.pas and user_service_intf_binder.pas
463465
464466 ws_helper\ws_helper.exe -i -b -o. user_service_intf.pas
465467 ws_helper, Web Service Toolkit 0.4 Copyright (c) 2006, 2007 by Inoussa OUEDRAOGO
466468 Parsing the file : user_service_intf.pas
467469 Proxy file generation...
468470 Binder file generation...
469471 Implementation file generation...
470472 Metadata file generation...
471473 File "user_service_intf.pas" parsed succesfully..
472474
473475The user_service_intf_imp.pas unit 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.
474476
475477``` pascal
476478Unit user_service_intf_imp;
477479{$IFDEF FPC} {$mode objfpc}{$H+} {$ENDIF}
478480Interface
479481Uses SysUtils, Classes,
480482 base_service_intf, server_service_intf, server_service_imputils,
481483 user_service_intf, cursor_intf;
482484
483485Type
484486 { TUserService_ServiceImp }
485487
486488 TUserService_ServiceImp=class(TBaseServiceImplementation,UserService)
487489 Protected
488490 function GetList():TUserArray;
489491 procedure Add(
490492 Const AUser : TUser
491493 );
492494 procedure Update(
493495 Const AUser : TUser
494496 );
495497 function Find(
496498 Const AName : string
497499 ):TUser;
498500 function Delete(
499501 Const AName : string
500502 ):boolean;
501503 End;
502504
503505 procedure RegisterUserServiceImplementationFactory();
504506
505507Implementation
506508(...)
507509
508510procedure TUserService_ServiceImp.Add(Const AUser : TUser);
509511var
510512 locObj : TUser;
511513Begin
512514 locObj := Find(AUser.UserName);
513515 if ( locObj <> nil ) then
514516 raise Exception.CreateFmt('Duplicated user : "%s"',[AUser.UserName]);
515517 locObj := TUser.Create();
516518 locObj.Assign(AUser);
517519 FUserList.Add(locObj);
518520End;
519521
520522procedure RegisterUserServiceImplementationFactory();
521523Begin
522524 GetServiceImplementationRegistry().Register(
523525 'UserService',
524526TImplementationFactory.Create(TUserService_ServiceImp) as IServiceImplementationFactory);
525527End;
526528
527529(...)
528530```
529531
530532#### Providing a binder for the service.
531533
532534The binder's role is to:
533535
534536- unpack the incoming message,
535537- set up the call stack,
536538- make the call against the registered implementation,
537539- serialize the execution stack to create the return message.
538540
539541The user_service_intf_binder.pas unit generated by ws_helper, contains :
540542
541543- TUserService_ServiceBinder : the actual binder class,
542544- TUserService_ServiceBinderFactory a factory class for the binder and
543545- Server_service_RegisterUserServiceService : the binder factory registration procedure.
544546
545547The following code extract shows the unit interface part and a method handler of the binder.
546548
547549``` pascal
548550unit user_service_intf_binder;
549551{$IFDEF FPC} {$mode objfpc}{$H+} {$ENDIF}
550552interface
551553uses SysUtils, Classes, base_service_intf, server_service_intf, user_service_intf;
552554
553555type
554556 TUserService_ServiceBinder=class(TBaseServiceBinder)
555557 Protected
556558 procedure GetListHandler(AFormatter:IFormatterResponse);
557559 procedure AddHandler(AFormatter:IFormatterResponse);
558560 procedure UpdateHandler(AFormatter:IFormatterResponse);
559561 procedure FindHandler(AFormatter:IFormatterResponse);
560562 procedure DeleteHandler(AFormatter:IFormatterResponse);
561563 Public
562564 constructor Create();
563565 End;
564566
565567 TUserService_ServiceBinderFactory = class(TInterfacedObject,IItemFactory)
566568 protected
567569 function CreateInstance():IInterface;
568570 End;
569571
570572 procedure Server_service_RegisterUserServiceService();
571573
572574(...)
573575
574576procedure TUserService_ServiceBinder.AddHandler(AFormatter:IFormatterResponse);
575577Var
576578 cllCntrl : ICallControl;
577579 tmpObj : UserService;
578580 callCtx : ICallContext;
579581 strPrmName : string;
580582 procName,trgName : string;
581583 AUser : TUser;
582584Begin
583585 callCtx := GetCallContext();
584586 TObject(AUser) := Nil;
585587
586588 strPrmName := 'AUser'; AFormatter.Get(TypeInfo(TUser),strPrmName,AUser);
587589 If Assigned(Pointer(AUser)) Then
588590 callCtx.AddObjectToFree(TObject(AUser));
589591
590592 tmpObj := Self.GetFactory().CreateInstance() as UserService;
591593 if Supports(tmpObj,ICallControl,cllCntrl) then
592594 cllCntrl.SetCallContext(GetCallContext());
593595
594596 tmpObj.Add(AUser);
595597
596598 procName := AFormatter.GetCallProcedureName();
597599 trgName := AFormatter.GetCallTarget();
598600 AFormatter.Clear();
599601 AFormatter.BeginCallResponse(procName,trgName);
600602 AFormatter.EndCallResponse();
601603
602604 callCtx := Nil;
603605End;
604606```
605607
606608#### Host the service into an application server.
607609
608610The application server's role is to route incoming service requests to the Web Service Toolkit runtime. For the runtime to process service requests :
609611
610612- The services and their implementations have to be registered ,
611613- The message protocol (SOAP, binary,...) have to be registered.
612614
613615The runtime interface is defined in the server_service_intf unit. This unit contains :
614616
615617- GetServerServiceRegistry, which returns the service registry,
616618- GetServiceImplementationRegistry which returns the service implementation registry,
617619- GetFormatterRegistry which returns the message format registry and
618620- HandleServiceRequest which is the unique entry point for request processing.
619621
620622The toolkit is provided with a simple TCP server ( using Synapse components ) hosting the sample UserService service defined early in this document and located in the \samples\tcp_server folder. The complete source files of the sample is in that directory and the client application in the \samples\user_client_console sub folder. The registrations are done in the application main routine as printed above:
621623
622624``` pascal
623625program tcp_server;
624626{$INCLUDE wst.inc}
625627uses
626628 Classes, SysUtils,
627629 base_service_intf, server_service_soap,
628630 base_binary_formatter, server_binary_formatter,
629631 metadata_service, metadata_service_imp, metadata_service_binder,
630632 synapse_tcp_server,
631633 user_service_intf, user_service_intf_binder, user_service_intf_imp , imp_helper;
632634var
633635 listnerThread : TServerListnerThread;
634636begin
635637 SetLogger(TConsoleLogger.Create());
636638
637639 Server_service_RegisterBinaryFormat();
638640 Server_service_RegisterSoapFormat();
639641 Server_service_RegisterWSTMetadataServiceService();
640642 RegisterWSTMetadataServiceImplementationFactory();
641643
642644 Server_service_RegisterUserServiceService();
643645 RegisterUserServiceImplementationFactory();
644646
645647 Logger().Log('WST sample TCP Server listning on "%s"',[sSERVER_PORT]);
646648 Logger().Log('Hit <enter> to stop.');
647649 listnerThread := TServerListnerThread.Create();
648650 ReadLn;
649651end.
650652```
651653
652654Server_service_RegisterUserServiceService located in the user_service_intf_binder unit ( generated by ws_helper ) registers the UserService service by calling in turn GetServerServiceRegistry:
653655
654656``` pascal
655657procedure Server_service_RegisterUserServiceService();
656658Begin
657659 GetServerServiceRegistry().Register(
658660 'UserService',TUserService_ServiceBinderFactory.Create() as IitemFactory
659661 );
660662End;
661663```
662664
663665Server_service_RegisterSoapFormat located in the server_service_soap unit ( provided by the toolkit ) registers the SOAP implementation by calling in turn GetFormatterRegistry:
664666
665667``` pascal
666668 procedure Server_service_RegisterSoapFormat();
667669 begin
668670 GetFormatterRegistry().Register(
669671 sSOAP_CONTENT_TYPE,
670672 TSimpleItemFactory.Create(TSOAPFormatter) as IitemFactory
671673 );
672674 RegisterStdTypes();
673675 end;
674676```
675677
676678Server_service_RegisterBinaryFormat located in the server_binary_formatter unit ( provided by the toolkit ) registers the Binary message implementation by calling in turn GetFormatterRegistry:
677679
678680``` pascal
679681 procedure Server_service_RegisterBinaryFormat();
680682 begin
681683 GetFormatterRegistry().Register(
682684 sCONTENT_TYPE,
683685 TBinaryFormatterFactory.Create() as IitemFactory
684686 );
685687 end;
686688```
687689
688690Incoming requests are processed in the client thread TClientHandlerThread.Execute() method (located in the synapse_tcp_server.pas file) invoking the HandleServiceRequest() method.
689691
690692``` pascal
691693procedure TClientHandlerThread.Execute();
692694var
693695 wrtr : IDataStore;
694696 rdr : IDataStoreReader;
695697 buff, trgt,ctntyp : string;
696698 rqst : IRequestBuffer;
697699 i : PtrUInt;
698700begin
699701 FInputStream := TMemoryStream.Create();
700702 FOutputStream := TMemoryStream.Create();
701703 FSocketObject := TTCPBlockSocket.Create();
702704 try
703705 FSocketObject.RaiseExcept := True;
704706 try
705707 FSocketObject.Socket := FSocketHandle;
706708 FSocketObject.GetSins();
707709 while not Terminated do begin
708710 FOutputStream.Size := 0;
709711 if ( ReadInputBuffer() >= SizeOf(LongInt) ) then begin
710712 rdr := CreateBinaryReader(FInputStream);
711713 trgt := rdr.ReadStr();
712714 ctntyp := rdr.ReadStr();
713715 buff := rdr.ReadStr();
714716 rdr := nil;
715717 FInputStream.Size := 0;
716718 FInputStream.Write(buff[1],Length(buff));
717719 FInputStream.Position := 0;
718720 rqst := TRequestBuffer.Create(trgt,ctntyp,FInputStream,FOutputStream);
719721 HandleServiceRequest(rqst);
720722 i := FOutputStream.Size;
721723 SetLength(buff,i);
722724 FOutputStream.Position := 0;
723725 FOutputStream.Read(buff[1],i);
724726 FOutputStream.Size := 0;
725727 wrtr := CreateBinaryWriter(FOutputStream);
726728 wrtr.WriteStr(buff);
727729 SendOutputBuffer();
728730 ClearBuffers();
729731 end;
730732 end;
731733 except
732734 on e : Exception do begin
733735 Logger().Log('Error : ThreadID = %d; Message = %s',[Self.ThreadID,e.Message]);
734736 end;
735737 end;
736738 finally
737739 FreeAndNil(FSocketObject);
738740 end;
739741end;
740742```
741743
742744In order to give it a try one have to :
743745
744746- compile the server ( \samples\tcp_server\tcp_server.lpi it is a console program),
745747- compile the client application ( \samples\user_client_console\user_client_console.lpi ),
746748- execute the server and start listening,
747749- execute the client.
748750
749751### WSDL generation
750752
751753Services in the toolkit are organized into meta data repositories. Conceptually a repository corresponds :
752754
753755- at compile time to the pascal unit containing the service definition
754756- at runtime to a name space.
755757
756758The repository is the toolkit WSDL generation unit.
757759
758760#### The Metadata Service
759761
760762The 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.
761763
762764#### WSDL generation API
763765
764766The **metadata_wsdl** pascal unit contains the **GenerateWSDL** function for WSDL generation from a repository (see the signature below).
765767
766768``` pascal
767769 PServiceRepository = ^TServiceRepository;
768770 TServiceRepository = record
769771 NameSpace : ShortString;
770772 Name : ShortString;
771773 RootAddress : ShortString;
772774 ServicesCount : Byte;
773775 Services : PService;
774776 end;
775777
776778 procedure GenerateWSDL(AMdtdRep : PServiceRepository; ADoc : TDOMDocument);
777779```
778780
779781##### WSDL Customization
780782
781783The 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.
782784
783785#### Sample
784786
785787A functional sample project is located under **\samples\http_server** . It is an Indy base http server.
786788
787789### Services Extensions
788790
789791Services 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.
790792
791793``` pascal
792794 TMessageStage = (
793795 msAfterDeserialize, msAfterSerialize, msBeforeDeserialize, msBeforeSerialize
794796 );
795797
796798 IServiceExtension = interface
797799 ['{E192E6B3-7932-4D44-A8AC-135D7A0B8C93}']
798800 procedure ProcessMessage(
799801 const AMessageStage : TMessageStage;
800802 ACallContext : ICallContext;
801803 AMsgData : IInterface
802804 );
803805 end;
804806```
805807
806808The **AMsgData** parameter actual type depends on the message processing state and corresponds to :
807809
808810- **IRequestBuffer** on "msBeforeDeserialize" and "msAfterSerialize"
809811- **IFormatterResponse** on "msAfterDeserialize" and "msBeforeSerialize"
810812
811813These 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
812814
813815``` pascal
814816 IServiceExtensionRegistry = Interface
815817 ['{68DC78F1-E6CF-4D6B-8473-75288794769C}']
816818 function Find(const AName : string):IServiceExtension;
817819 procedure Register(
818820 const AName : string;
819821 AFactory : IItemFactory
820822 );
821823 end;
822824```
823825
824826In 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** ).
825827
826828## Services meta data
827829
828830Services in the toolkit are organized into ***meta data repositories( see the “services's meta data” below )***. Conceptually a repository corresponds :
829831
830832- at compile time to the pascal unit containing the service definition
831833- at runtime to a name space.
832834
833835The **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.
834836
835837``` pascal
836838 IModuleMetadataMngr = interface
837839 ['{B10ACF6A-A599-45A3-B083-BEEFB810C889}']
838840 function IndexOfName(const ARepName : shortstring):Integer;
839841 function GetCount():Integer;
840842 function GetRepositoryName(const AIndex : Integer):shortstring;
841843 procedure SetRepositoryNameSpace(const ARepName,ANameSpace : shortstring);
842844 function LoadRepositoryName(
843845 const ARepName,ARootAddress : shortstring;
844846 out ARepository : PServiceRepository
845847 ):Integer;
846848 procedure ClearRepository(var ARepository : PServiceRepository);
847849 procedure SetServiceCustomData(
848850 const ARepName : shortstring;
849851 const AServiceName : shortstring;
850852 const ADataName,
851853 AData : string
852854 );
853855 procedure SetOperationCustomData(
854856 const ARepName : shortstring;
855857 const AServiceName : shortstring;
856858 const AOperationName : shortstring;
857859 const ADataName,
858860 AData : string
859861 );
860862 function GetServiceMetadata(const ARepName,AServiceName : shortstring) : PService;
861863 procedure ClearServiceMetadata(var AService : PService);
862864 end;
863865```
864866
865867### Extended Meta data
866868
867869The 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** .
868870
869871``` pascal
870872 initialization
871873 {$i ebay.lrs}
872874
873875 {$IF DECLARED(Register_ebay_ServiceMetadata)}
874876 Register_ebay_ServiceMetadata();
875877 {$ENDIF}
876878 End.
877879```
878880
879881## Headers support
880882
881883### The THeaderBlock class
882884
883885``` pascal
884886 THeaderBlock = class(TBaseComplexRemotable)
885887 public
886888 property Direction : THeaderDirection read FDirection write FDirection;
887889 property Understood : Boolean read FUnderstood write FUnderstood;
888890 published
889891 property mustUnderstand : Integer read FmustUnderstand write SetmustUnderstand
890892 stored HasmustUnderstand;
891893 end;
892894```
893895
894896The **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.
895897
896898### Defining header class
897899
898900Soap 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.
899901
900902``` pascal
901903 TCalcHeader = class(THeaderBlock)
902904 published
903905 property Login : string read FLogin write FLogin;
904906 property Password : string read FPassword write FPassword;
905907 property WantedPrecision : Integer read FWantedPrecision write FWantedPrecision;
906908 end;
907909```
908910
909911### The ICallContext interface
910912
911913``` pascal
912914 ICallContext = Interface
913915 ['{855EB8E2-0700-45B1-B852-2101023200E0}']
914916 procedure AddObjectToFree(const AObject : TObject);
915917 procedure Clear();
916918 function AddHeader(
917919 const AHeader : THeaderBlock;
918920 const AKeepOwnership : Boolean
919921 ):Integer;
920922 function GetHeaderCount(const ADirections : THeaderDirections):Integer;
921923 function GetHeader(const AIndex : Integer) : THeaderBlock;
922924 procedure ClearHeaders(const ADirection : THeaderDirection);
923925 End;
924926```
925927
926928The **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.
927929
928930### Client side headers
929931
930932An **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.
931933
932934``` pascal
933935 var
934936 ch : TCalcHeader;
935937 hdrs : ICallContext;
936938 begin
937939 FObj := TCalculator_Proxy.Create('Calculator', edtFormat.Text, edtAddress.Text);
938940
939941 ch := TCalcHeader.Create();
940942 ch.mustUnderstand := 1;
941943 ch.Login := 'azerty';
942944 ch.Password := 'qwerty';
943945 ch.WantedPrecision := 1210;
944946 hdrs := FObj as ICallContext;
945947 hdrs.AddHeader(ch,true);
946948```
947949
948950A header may be made mandatory by setting its **mustUnderstand** property to 1 as in the code above.
949951
950952### Server side headers
951953
952954#### The ICallControl interface
953955
954956``` pascal
955957 ICallControl = interface
956958 ['{7B4B7192-EE96-4B52-92C7-AE855FBC31E7}']
957959 procedure SetCallContext(ACallContext : ICallContext);
958960 function GetCallContext():ICallContext;
959961 end;
960962```
961963
962964The **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.
963965
964966``` pascal
965967 function TCalculator_ServiceImp.AddInt(
966968 Const A : Integer;
967969 Const B : Integer
968970 ):TBinaryArgsResult;
969971 var
970972 hdr : TCalcResultHeader;
971973 h : TCalcHeader;
972974 cc : ICallContext;
973975 Begin
974976 hdr := TCalcResultHeader.Create();
975977 cc := GetCallContext();
976978 if Assigned(cc) and ( cc.GetHeaderCount([hdIn]) > 0 ) and ( cc.GetHeader(0).InheritsFrom(TCalcHeader) ) then begin
977979 h := cc.GetHeader(0) as TCalcHeader;
978980 h.Understood := True;
979981 hdr.Assign(h);
980982 end;
981983 hdr.TimeStamp := DateTimeToStr(Now());
982984 hdr.SessionID := 'testSession';
983985 cc.AddHeader(hdr,True);
984986 hdr := nil;
985987 Result := TBinaryArgsResult.Create();
986988 Try
987989 Result.Arg_OP := '+';
988990 Result.Arg_OpEnum := coAdd;
989991 Result.Arg_A := A;
990992 Result.Arg_B := B;
991993 Result.Arg_R := A + B;
992994 Result.Comment := 'Doing an + operation';
993995 Except
994996 FreeAndNil(Result);
995997 Raise;
996998 End;
997999 End;
9981000```
9991001
10001002## SOAP Specific
10011003
10021004### Binding style
10031005
10041006The binding style is used to indicate whether the service is **RPC** oriented or **Document** oriented.
10051007
10061008#### Client side
10071009
10081010The 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.
10091011
10101012``` pascal
10111013 locService := TSampleService_Proxy.Create(
10121014 'SampleService',
10131015 'SOAP:Style=Document;EncodingStyle=Litteral',
10141016 'http:Address=http://127.0.0.1/services/SampleService'
10151017 );
10161018```
10171019
10181020#### Server side
10191021
10201022Currently services created with the toolkit use the **RPC** binding style.
10211023
10221024### Encoding style
10231025
10241026The encoding style indicates the rules used to encode types in XML. Supported values are **Encoded** and **Litteral**.
10251027
10261028#### Client side
10271029
10281030The 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.
10291031
10301032#### Server side
10311033
10321034Currently services created with the toolkit use the **Encoded** encoding style.
10331035
10341036## Provided examples
10351037
10361038The samples are located under the **“tests”** folder.
10371039
10381040### Client side examples ( tested on Windows XP and Ubuntu )
10391041
10401042- 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)
10411043- Google sample : It demonstrates use of class and array data types .
10421044- Metadata Browser : This sample demonstrates use of class and array data types and mainly the toolkit metadata service.
10431045- eBay sample, this sample uses OpenSLL which can be found at <http://www.openssl.org> and SYNAPSE ( <http://www.ararat.cz/synapse/> ).
10441046- \samples\delphi\user_client_console : Delphi ( compile with Delphi 7) client sample. Used protocol : the TCP, HTTP, LIBRARY; Used format : BINARY.
10451047
10461048### Server side examples
10471049
10481050- samples\tcp_server : This is a sample TCP server based on the Synapse components. It uses the UserService.
10491051- 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.
10501052- 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.
10511053
10521054## Status
10531055
10541056The 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.
10551057
10561058### Serialization
10571059
10581060The serialization is based on the IFormatterBase interface located in the **base_service_intf** unit.
10591061
10601062The toolkit has two serializers implementations : the **SOAP serializer** and a **Binary serializer**.
10611063
10621064#### *SOAP serializer*
10631065
10641066The SOAP serializer implements SOAP 1.1. It has support for the following pascal types:
10651067
10661068- Available integers :
10671069 - Byte mapped to unsignedByte
10681070 - ShortInt mapped to byte
10691071 - SmallInt mapped to short
10701072 - Word mapped to unsignedShort
10711073 - LongInt mapped to int
10721074 - LongWord mapped to unsignedInt
10731075 - Int64 mapped to long
10741076 - QWord mapped to int
10751077
10761078- String mapped to string
10771079- Boolean mapped to boolean
10781080- Enumerations mapped to their string representation
10791081
10801082- Float types :
10811083 - Single mapped to float
10821084 - Double mapped to double
10831085 - Extended mapped to double
10841086 - Currency mapped to float
10851087
10861088- 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.
10871089
10881090#### *Binary serializer*
10891091
10901092The Binary serializer is more efficient in time and space compared to the SOAP serializer . It uses big endian to stream data. This serializer has been tested with Delphi 7 ( \samples\delphi\user_client_console ) It has support for the following pascal types:
10911093
10921094- Available integers :
10931095 - Byte
10941096 - ShortInt
10951097 - SmallInt
10961098 - Word
10971099 - LongInt
10981100 - LongWord
10991101 - Int64
11001102 - QWord
11011103
11021104- String
11031105- Boolean
11041106- Enumerations
11051107
11061108- Float types :
11071109 - Single
11081110 - Double
11091111 - Extended
11101112 - Currency
11111113
11121114- 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.
11131115
11141116#### *Class type serialization*
11151117
11161118The 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.
11171119
11181120##### The root **“TBaseRemotable”** class
11191121
11201122``` pascal
11211123 TBaseRemotable = class(TPersistent)
11221124 Public
11231125 constructor Create();virtual;
11241126 class procedure Save(
11251127 AObject : TBaseRemotable;
11261128 AStore : IFormatterBase;
11271129 Const AName : String;
11281130 Const ATypeInfo : PTypeInfo
11291131 );virtual;abstract;
11301132 class procedure Load(
11311133 Var AObject : TObject;
11321134 AStore : IFormatterBase;
11331135 var AName : String;
11341136 const ATypeInfo : PTypeInfo
11351137 );virtual;abstract;
11361138 End;
11371139```
11381140
11391141**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 :
11401142
11411143- **Save** : this method is called when the toolkit needs to serialize the **AObject** parameter.
11421144- **Load**: this method is called when the toolkit needs to un-serialize to the **AObject** parameter.
11431145
11441146##### The “TBaseComplexRemotable” serialization
11451147
11461148``` pascal
11471149 TBaseComplexRemotable = class(TAbstractComplexRemotable)
11481150 public
11491151 class procedure Save(
11501152 AObject : TBaseRemotable;
11511153 AStore : IFormatterBase;
11521154 const AName : string;
11531155 const ATypeInfo : PTypeInfo
11541156 );override;
11551157 class procedure Load(
11561158 var AObject : TObject;
11571159 AStore : IFormatterBase;
11581160 var AName : string;
11591161 const ATypeInfo : PTypeInfo
11601162 );override;
11611163 class procedure RegisterAttributeProperty(const AProperty : shortstring);virtual;
11621164 class procedure RegisterAttributeProperties(const APropertList : array of shortstring);virtual;
11631165 class function IsAttributeProperty(const AProperty : shortstring):Boolean;
11641166 procedure Assign(Source: TPersistent); override;
11651167 end;
11661168```
11671169
11681170**TBaseComplexRemotable** implements serialization for its descendants classes published properties. The serialization is based on runtime type information (RTTI) and can be customized to:
11691171
11701172- ignore always some published properties.
11711173- ignore conditionally some published properties.
11721174
11731175The following class shows a the serialization's customization sample.
11741176
11751177``` pascal
11761178 TSampleClass = class(TBaseComplexRemotable)
11771179 private
11781180 FProp_Always: Integer;
11791181 FProp_Never: Integer;
11801182 FProp_Optional: Integer;
11811183 function GetStoredProp_Optional: boolean;
11821184 published
11831185 //This property will always be serialized
11841186 property Prop_Always : Integer read FProp_Always write FProp_Always;
11851187 //This property will never be serialized
11861188 property Prop_Never : Integer read FProp_Never write FProp_Never stored False;
11871189 //This property will be serialized if "Self.GetStoredProp_Optional() = True"
11881190 property Prop_Optional : Integer read FProp_Optional write FProp_Optional stored GetStoredProp_Optional;
11891191 End;
11901192```
11911193
11921194- Attribute properties
11931195
11941196TBaseComplexRemotable allows properties serialization as attributes. Theses properties have to be registered as such with the RegisterAttributeProperty class method or RegisterAttributeProperties one.
11951197
11961198##### TBaseComplexRemotable
11971199
11981200**TBaseComplexSimpleContentRemotable** provides implementation for the “XML Schema” complex types which extend simple types with attributes. The following example illustrates this :
11991201
12001202``` xml
12011203 <xs:complexType name="DecimalWithUnits">
12021204 <xs:simpleContent>
12031205 <xs:extension base="xs:decimal">
12041206 <xs:attribute name="Units" type="xs:string"
12051207 use="required"/>
12061208 </xs:extension>
12071209 </xs:simpleContent>
12081210 </xs:complexType>
12091211```
12101212
12111213This type will be translate by ws_helper to Pascal as
12121214
12131215``` pascal
12141216 DecimalWithUnits = class(TComplexFloatExtendedContentRemotable)
12151217 private
12161218 FUnits : string;
12171219 published
12181220 property Units : string read FUnits write FUnits;
12191221 end;
12201222```
12211223
12221224using the predefined types ( in base_service_intf.pas )
12231225
12241226``` pascal
12251227 TBaseComplexSimpleContentRemotable =
12261228 class(TAbstractComplexRemotable)
12271229 protected
12281230 class procedure SaveValue(
12291231 AObject : TBaseRemotable;
12301232 AStore : IformatterBase
12311233 );virtual;abstract;
12321234 class procedure LoadValue(
12331235 var AObject : TObject;
12341236 AStore : IformatterBase
12351237 );virtual;abstract;
12361238 public
12371239 class procedure Save(
12381240 AObject : TBaseRemotable;
12391241 AStore : IFormatterBase;
12401242 const AName : string;
12411243 const ATypeInfo : PTypeInfo
12421244 );override;
12431245 class procedure Load(
12441246 var AObject : TObject;
12451247 AStore : IFormatterBase;
12461248 var AName : string;
12471249 const ATypeInfo : PTypeInfo
12481250 );override;
12491251 end;
12501252
12511253 TComplexFloatExtendedContentRemotable =
12521254 class(TBaseComplexSimpleContentRemotable)
12531255 private
12541256 FValue: Extended;
12551257 protected
12561258 class procedure SaveValue(
12571259 AObject : TBaseRemotable;
12581260 AStore : IformatterBase
12591261 );override;
12601262 class procedure LoadValue(
12611263 var AObject : TObject;
12621264 AStore : IformatterBase
12631265 );override;
12641266 public
12651267 property Value : Extended read FValue write FValue;
12661268 end;
12671269```
12681270
12691271An 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, ...).
12701272
12711273``` xml
12721274 <example Units = "meter">
12731275 12.10
12741276 </example>
12751277```
12761278
12771279##### Provided array implementations
12781280
12791281The toolkit provides array implementation for basic types ( in the **base_service_intf** unit ) listed bellow. The implementations are based on the serialization's customization.
12801282
12811283- Available integers :
12821284 - Byte **TArrayOfInt8URemotable**
12831285 - ShortInt **TArrayOfInt8SRemotable**
12841286 - SmallInt **TArrayOfInt16SRemotable**
12851287 - Word **TArrayOfInt16URemotable**
12861288 - LongInt **TArrayOfInt32SRemotable**
12871289 - LongWord **TArrayOfInt32URemotable**
12881290 - Int64 **TArrayOfInt64SRemotable**
12891291 - Qword **TArrayOfInt64URemotable**
12901292- String **TarrayOfStringRemotable**( AnsiString )
12911293- Boolean **TArrayOfBooleanRemotable**
12921294- Float types :
12931295 - Single **TArrayOfFloatSingleRemotable**
12941296 - Double **TArrayOfFloatDoubleRemotable**
12951297 - Extended **TArrayOfFloatExtendedRemotable**
12961298 - Currency **TArrayOfFloatCurrencyRemotable**
12971299
12981300The 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 ):
12991301
13001302``` xml
13011303 <xs:complexType name="CustomerContentSearchRequest">
13021304 <xs:sequence>
13031305 <xs:element name="CustomerPage" type="xs:positiveInteger"
13041306 minOccurs="0"/>
13051307 <xs:element name="Email" type="xs:string" minOccurs="0"/>
13061308 <xs:element name="Name" type="xs:string" minOccurs="0"/>
13071309 <xs:element name="ResponseGroup" type="xs:string"
13081310 minOccurs="0" maxOccurs="unbounded"/>
13091311 </xs:sequence>
13101312 </xs:complexType>
13111313```
13121314
13131315which could be instantiated as
13141316
13151317``` xml
13161318 <search>
13171319 <CustomerPage> 1 </CustomerPage>
13181320 <Name>Sample name</Name>
13191321 <ResponseGroup>Group 1</ResponseGroup>
13201322 <ResponseGroup>Group 2</ResponseGroup>
13211323 <ResponseGroup>Group 3</ResponseGroup>
13221324 </search>
13231325```
13241326
13251327This type will be translate to Pascal by ws_helper as (the private and protected parts are omitted to be short)
13261328
13271329``` pascal
13281330(...)
13291331 CustomerContentSearchRequest_ResponseGroupArray =
13301332 class(TBaseSimpleTypeArrayRemotable)
13311333 public
13321334 class function GetItemTypeInfo():PTypeInfo;override;
13331335 procedure SetLength(const ANewSize : Integer);override;
13341336 property Item[AIndex:Integer] : string
13351337 read GetItem write SetItem; default;
13361338 end;
13371339
13381340 CustomerContentSearchRequest = class(TBaseComplexRemotable)
13391341 published
13401342 property CustomerPage : positiveInteger
13411343 read FCustomerPage
13421344 write FCustomerPage stored HasCustomerPage;
13431345 property Email : string
13441346 read FEmail
13451347 write FEmail
13461348 stored HasEmail;
13471349 property Name : string read FName write FName stored HasName;
13481350 property ResponseGroup :
13491351 CustomerContentSearchRequest_ResponseGroupArray
13501352 read FResponseGroup
13511353 write FResponseGroup;
13521354 end;
13531355
13541356implementation
13551357(...)
13561358 GetTypeRegistry().ItemByTypeInfo[
13571359 TypeInfo(CustomerContentSearchRequest_ResponseGroupArray)]
13581360 .RegisterExternalPropertyName(sARRAY_STYLE,sEmbedded);
13591361(...)
13601362```
13611363
13621364The last instruction set the array style to “Embedded” and so the SOAP formatter will serialize the array accordingly.
13631365
13641366#### *Test cases*
13651367
13661368The toolkit uses FPCUnit for test cases. The test project is located in the **\tests\test_suite** folder.
13671369
13681370## TODO
13691371
13701372### TODO Common
13711373
13721374- Simple type support in headers
13731375- Header support for the binary format
13741376- True Attribute serialization support for the binary format
13751377
13761378### TODO Client-Side
13771379
13781380- ~~Basic array support~~ for SOAP
13791381- ~~Basic array support~~ for Binary format
13801382- XML-RPC formatter
13811383- More documentation and samples !
13821384 - ~~eBay basic client~~ : demonstrates the **GetPopularKeywords** operation call
13831385 - ~~"Amazon E-Commerce Service" sample~~
13841386- ~~WSDL to pascal compiler~~
13851387- Enhance the parser
13861388 - ~~To allow comments in the input file of ws_helper~~ : **{}** comment style are now supported
13871389- Client side services extensions
13881390
13891391### TODO Server-Side
13901392
13911393Extend the toolkit to Server side for :
13921394
13931395- ~~SOAP~~
13941396- ~~Binary serialization~~
13951397- ~~Bytes ordering in binary serialization : alaways use big-endian~~
13961398- XML-RPC
13971399- ~~TCP transport~~ ( first implementation).
13981400- ~~WSDL generation~~
13991401- More documentation and samples !
14001402- ~~Apache support~~ : services as Apache modules using Sekelsenmat 's \[\[:fpc:FPC_and_Apache_Modules \| Apache headers translation
14011403
14021404\]\]
14031405
14041406- - See the **apache_module** sample located in the ***tests\apache_module*** folder
14051407- Classes inheritance generation in WSDL
14061408
14071409## Licence
14081410
14091411- The support units are provided under modified LGPL
14101412- ws_helper sources are provided under GPL 2 ( or later version )
14111413
14121414## Download & NewsGroup
14131415
14141416The 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).\
14151417The "Web Service Toolkit" now has a newsgroup hosted at <news://news.dxmachine.com/public.wst>
14161418
14171419## Changes Log
14181420
14191421### Version 0.4
14201422
14211423- WSDL to Pascal translation support in "ws_helper"
14221424- new TCP transport implementation ( using synapse library ) in synapse_tcp_protocol.pas
14231425- new library protocol implementation in library_protocol.pas
14241426- TCP server implementation ( using synapse library ) in synapse_tcp_server.pas
14251427- Delphi : first binary format support
14261428- Embedded array support
14271429- Object Pascal reserved words can now be used as service methods's name, enumeration, ... ( see TTypeRegistryItem.RegisterExternalPropertyName() )
14281430- The toolkit can now be used with FPC without Lazarus
14291431- "Amazon E-Commerce Service" sample
14301432- Bugs Fixes.
14311433
14321434### Version 0.3.1 ( 21 August 2006 )
14331435
14341436- Apache Web Server support : services hosting as Apache's module.
14351437 - See the **apache_module** sample located in the ***tests\apache_module*** folder.
14361438- 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**.
14371439- Bugs Fixes.
14381440
14391441### Version 0.3 ( 5 August 2006 )
14401442
14411443- Header support ( client and server side )
14421444- Server side service extensions
14431445- Attribute serialization
14441446- New transport implementation : Synapse HTTP client support
14451447- Address per operation support ( client side )
14461448- Extended meta data
14471449- Bug Fixes
14481450
14491451### Version 0.2.3.2 ( 5 July 2006 )
14501452
14511453- ICS and Indy HTTP Proxy "user" and "passeword" support.
14521454
14531455### Version 0.2.3 ( 4 July 2006 )
14541456
14551457- WSDL generation
14561458- Metadata service
14571459- Metadata Browser sample
14581460- HTTP server sample
14591461- Pascal basic types array implementation
14601462- The ws_helper's parser now supports:
14611463 - {} comment style in the input file
14621464 - service interfaces may have GUID
14631465- more test cases
14641466- bug fix
14651467
14661468### Version 0.2.2 ( 7 June 2006 )
14671469
14681470- All pascal basic types are supported by the **SOAP serializer** and the **Binary serializer** ( Available integers, available floats, string, boolean, Enumerations, class intances )
14691471- Array support for Binary serializer
14701472- FPCUnit test cases
14711473 - SOAP serializer ( basic types and classes instances )
14721474 - Binary serializer ( basic types and classes instances )
14731475- All interfaces now have GUID
14741476
14751477## Author
14761478
14771479Inoussa OUEDRAOGO, <http://inoussa12.googlepages.com/>
14781480
14791481---
14801482*From the Free Pascal wiki, page "Web Service Toolkit/pt", as it stood on 2023-02-06 after a change by Kai Burghardt, 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).*
14811483Category: Pages for deletion

Back to history