unit uRODLToWSDL; {----------------------------------------------------------------------------} { RemObjects SDK Library - CodeGen } { } { compiler: Delphi 5 and up, Kylix 2 and up } { platform: Win32, Linux } { } { (c)opyright RemObjects Software. all rights reserved. } { } { Using this code requires a valid license of the RemObjects SDK } { which can be obtained at http://www.remobjects.com. } {----------------------------------------------------------------------------} {$IFDEF LINUX} {$I ../RemObjects.inc} {$ELSE} {$I ..\RemObjects.inc} {$ENDIF LINUX} interface uses {$IFDEF REMOBJECTS_TRIAL}uROTrial,{$ENDIF} Classes, uRODL, uROTypes, uROXMLSerializer; const SOAPDataTypes : array[TRODataType] of string = ( 'int', 'dateTime', 'double', 'double', 'string', 'string', 'long', 'boolean', 'anyType', dts_base64Binary, 'any', 'string', 'decimal', '???'); type { TRODLToWSDL } TRODLToWSDL = class(TRODLConverter) private fLocation: string; fShowClientId: Boolean; fUseLiteral: Boolean; fUseDocument: Boolean; fTargetNamespace: string; fExternalTypesAsReferences: Boolean; fExternalRefs, // namespace fExternalUrls: TStrings; // uri procedure SetLocation(const Value: string); procedure WriteEnum(anEnum : TRODLEnum); procedure WriteStruct(const aLibrary: TRODLLibrary; aStruct : TRODLStruct); procedure WriteArray(anArray : TRODLArray); procedure WriteMessages(aLibrary: TRODLLibrary; aService : TRODLService); procedure WriteLiteralParameters(aLibrary: TRODLLibrary; aService : TRODLService); procedure WriteBindings(aLibrary: TRODLLibrary; aService : TRODLService); procedure WritePorts(aLibrary: TRODLLibrary; aService : TRODLService); procedure WriteService(aLibrary: TRODLLibrary; aService : TRODLService); function GetAnchestor(aLibrary: TRODLLibrary; aService: TRODLService): TRODLService; procedure WriteAnnotation(aDocString: string; aIndentation: Integer = 0; aNs: string = 'xs:'); procedure WriteDocumentation(aDocString: string; aIndentation: Integer = 0; aNs: string = 'xs:'); function ExtSOAPDataType(aLibrary: TRODLLibrary; const aDataTypeName : string) : string; protected procedure IntConvert(const aLibrary : TRODLLibrary; const aTargetEntity : string = ''); override; procedure AddExternal(aNode: TRODLEntity); public constructor Create(const aLibraryFile: string; const aTargetEntity: string = ''); overload; override; constructor Create(const aLibrary: TRODLLibrary; const aTargetEntity: string = ''); overload; override; destructor Destroy; override; property Location : string read fLocation write SetLocation; property TargetNamespace: string read fTargetNamespace write fTargetNamespace; property ShowClientId : Boolean read fShowClientId write fShowClientId; property UseLiteral : Boolean read fUseLiteral write fUseLiteral; property UseDocument : Boolean read fUseDocument write fUseDocument; property ExternalTypesAsReferences : Boolean read fExternalTypesAsReferences write fExternalTypesAsReferences; end; function SOAPDataType(const aDataTypeName : string; IncludeNamespace : boolean = TRUE) : string; implementation uses SysUtils; function SOAPDataType(const aDataTypeName : string; IncludeNamespace : boolean = TRUE) : string; var dt : TRODataType; begin dt := StrToDataType(aDataTypeName); if (dt=rtUserDefined) then result := aDataTypeName else result := SOAPDataTypes[dt]; if IncludeNamespace then begin if (dt=rtUserDefined) then result := ns_Custom+':'+result else result := ns_Standard+':'+result; end; end; { TRODLToWSDL } const definitions_ns : array[0..6] of string = ('xmlns="http://schemas.xmlsoap.org/wsdl/" ', 'xmlns:xs="http://www.w3.org/2001/XMLSchema" ', 'name="%s" ', 'xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" ', 'xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" ', 'xmlns:mime="http://schemas.xmlsoap.org/wsdl/mime/" ', 'xmlns:'+ns_Custom+'="urn:%s"'); procedure TRODLToWSDL.IntConvert(const aLibrary: TRODLLibrary; const aTargetEntity: string); var s, i: integer; lService: TRODLService; begin with aLibrary do begin if (aTargetEntity<>'') then begin lService := aLibrary.FindService(aTargetEntity); if (lService <> nil) then if lService.isPrivate then Exit; end else lService := NIL; Write(''); Write(''); WriteAnnotation(aLibrary.Documentation); {Giovanni} // Write types Write('', 3); Write(Format('', [Name, Name]), 6); for i := 0 to fExternalRefs.Count -1 do begin Write(Format('',[fExternalRefs[i], fExternalUrls[i]] ), 3); end; for i := 0 to (EnumCount-1) do WriteEnum(Enums[i]); for i := 0 to (StructCount-1) do WriteStruct(aLibrary, Structs[i]); for i := 0 to (ArrayCount-1) do WriteArray(Arrays[i]); if fUseLiteral and fUseDocument then begin if (aTargetEntity<>'') then WriteLiteralParameters(aLibrary, lService) else for s := 0 to (ServiceCount-1) do begin lService := Services[s]; WriteLiteralParameters(aLibrary, lService); end; if fShowClientId then begin Write('', 3); Write('', 6); Write('', 9); Write('', 6); Write('', 9); Write('', 6); Write('', 3); end; end; Write('', 6); Write('', 3); // Writes messages if (aTargetEntity<>'') then WriteMessages(aLibrary, lService) else for s := 0 to (ServiceCount-1) do begin lService := Services[s]; WriteMessages(aLibrary, lService); end; if fShowClientId and fUseLiteral and fUseDocument then begin Write('', 3); Write('', 3); Write('', 3); end; // Writes port and operations if (aTargetEntity<>'') then WritePorts(aLibrary, lService) else for s := 0 to (ServiceCount-1) do begin lService := Services[s]; WritePorts(aLibrary, lService); end; // Write bindings if (aTargetEntity<>'') then WriteBindings(aLibrary, lService) else for s := 0 to (ServiceCount-1) do begin lService := Services[s]; WriteBindings(aLibrary, lService); end; // Writes services if (aTargetEntity<>'') then WriteService(aLibrary, lService) else for s := 0 to (ServiceCount-1) do begin lService := Services[s]; WriteService(aLibrary, lService); end; Write(''); end; end; procedure TRODLToWSDL.SetLocation(const Value: string); begin fLocation := Value; end; procedure TRODLToWSDL.WriteArray(anArray: TRODLArray); var lMin, lMax: Integer; begin if fExternalTypesAsReferences and (anArray.Attributes.Values['ImportedFromUrl'] <> '') then exit; Write(Format('', [anArray.Name]), 9); WriteAnnotation(anArray.Documentation, 9); if fUseDocument then begin Write('', 12); lMax := StrToIntDef(anArray.Attributes.Values['MaxOccurs'], -1); lMin := StrToIntDef(anArray.Attributes.Values['MinOccurs'], 0); if lMax = -1 then begin Write(Format('', [SOAPDataType(anArray.ElementType, false), lMin, ExtSOAPDataType(anArray.OwnerLibrary, anArray.ElementType)]), 15); end else begin Write(Format('', [SOAPDataType(anArray.ElementType, false), lMin, lMax, ExtSOAPDataType(anArray.OwnerLibrary, anArray.ElementType)]), 15); end; Write('', 12); end else begin Write('', 12); Write('', 15); Write('', 18); Write(Format('', [ExtSOAPDataType(anArray.OwnerLibrary, anArray.ElementType)]), 18); Write('', 15); Write('', 12); end; Write('', 9); end; procedure TRODLToWSDL.WriteEnum(anEnum: TRODLEnum); var i : integer; begin if fExternalTypesAsReferences and (anEnum.Attributes.Values['ImportedFromUrl'] <> '') then exit; Write(Format('', [anEnum.Name]), 9); WriteAnnotation(anEnum.Documentation, 12); {Giovanni} Write('', 12); for i := 0 to anEnum.Count-1 do begin //WriteDocumentation(anEnum.Items[i].Documentation, 12); {Giovanni} Write(Format('', [anEnum.Items[i].Name]), 15); end; Write('', 12); Write('', 9); end; function TRODLToWSDL.GetAnchestor(aLibrary: TRODLLibrary; aService: TRODLService): TRODLService; begin result := NIL; if (aService.Ancestor<>'') and not aService.isPrivate then result := aLibrary.FindService(aService.Ancestor) end; procedure TRODLToWSDL.WriteMessages(aLibrary: TRODLLibrary; aService: TRODLService); var o, p : integer; dups : TStringList; s, svcname, mtdname : string; op : TRODLOperation; begin // Writes all the methods of this service and its anchestors. // If more than one service descend from the same base one, the WSDL has to be generated // using a format like this: http://localhost:8099/SOAP?Service=ServiceOne svcname := aService.Name; dups := TStringList.Create; dups.Duplicates := dupIgnore; dups.Sorted := TRUE; try while Assigned(aService) and not aService.isPrivate do begin with aService.Default do begin for o := 0 to (Count-1) do begin op := Items[o]; // If a method with this name is present, it skips it mtdname := UpperCase(op.Name); if (dups.IndexOf(mtdname)>=0) then Continue else dups.Add(mtdname); if fUseLiteral and fUseDocument then begin Write(Format('', [svcname, op.Name]), 3); s := op.Attributes.Values['SOAPInputName']; if s = '' then s := Format('%s___%s', [svcname, op.Name]); Write(Format('', [s]), 6); Write('', 3); Write(Format('', [svcname, op.Name]), 3); s := op.Attributes.Values['SOAPOutputName']; if s = '' then s := Format('%s___%sResponse', [svcname, op.Name]); Write(Format('', [s]), 6); Write('', 3); end else begin // Continues with Items[o] do begin // Request Write(Format('', [svcname, op.Name]), 3); for p := 0 to (Count-1) do if IsInputFlag(Items[p].Flag) then Write(Format('', [Items[p].Name, ExtSOAPDataType(aLibrary, Items[p].DataType)]), 6); Write('', 3); // Response Write(Format('', [svcname, op.Name]), 3); if Assigned(aService.Default.Items[o].Result) then Write(Format('', [op.Result.Name, ExtSOAPDataType(aLibrary, op.Result.DataType)]), 6); //Write(Format('', [SOAPDataType(aService.Default.Items[o].Result.DataType)]), 6); for p := 0 to (Count-1) do begin if IsOutputFlag(Items[p].Flag) then Write(Format('', [Items[p].Name, ExtSOAPDataType(aLibrary, Items[p].DataType)]), 6); end; Write('', 3); end; end; end; end; aService := GetAnchestor(aLibrary, aService); end; finally dups.Free; end; end; procedure TRODLToWSDL.WritePorts(aLibrary: TRODLLibrary; aService: TRODLService); var o : integer; svcname: string; begin // Writes a port for each method of this service and its anchestors. // Refer to the comment in TRODLToWSDL.WriteMessages if aService.isPrivate then Exit; svcname := aService.Name; Write(Format('', [svcname]), 3); WriteDocumentation(aService.Documentation, 6,''); while Assigned(aService) and not aService.isPrivate do begin for o := 0 to (aService.Default.Count-1) do begin with aService.Default.Items[o] do begin Write(Format('', [Name]), 6); WriteDocumentation(Documentation, 6,''); {Giovanni} Write(Format('', [svcname, Name]), 9); Write(Format('', [svcname, Name]), 9); Write(Format('', [Name]), 6) end; end; aService := GetAnchestor(aLibrary, aService); end; Write('', 3); end; procedure TRODLToWSDL.WriteBindings(aLibrary: TRODLLibrary; aService: TRODLService); var o : integer; svcname : string; begin // Write all the bindings for this service and its anchestors using the method names. // It's important to notice that we NEVER use the anchestor name when composing the SOAPAction, but // always use the final service name if aService.isPrivate then Exit; svcname := aService.Name; Write(Format('', [svcname, svcname]), 3); WriteAnnotation(aService.Documentation, 6); {Giovanni} if fUseDocument then Write('', 6) else Write('', 6); while Assigned(aService) and not aService.isPrivate do begin for o := 0 to (aService.Default.Count-1) do begin with aService.Default.Items[o] do begin Write(Format('', [Name]), 9); if fUseDocument then Write(Format('', [aLibrary.Name, svcname, Name]),12) else Write(Format('', [aLibrary.Name, svcname, Name]),12); if fUseLiteral then begin Write('', 12); Write('', 15); if fShowClientId and fUseDocument then write('', 15); Write('', 12); Write('', 12); Write('', 15); if fShowClientId and fUseDocument then write('', 15); Write('', 12); end else begin Write('', 12); Write(Format('', [aLibrary.Name, svcname]), 15); Write('', 12); Write('', 12); Write(Format('', [aLibrary.Name, svcname]), 15); Write('', 12); end; Write('', 9); end; end; aService := GetAnchestor(aLibrary, aService); end; Write('', 3); end; procedure TRODLToWSDL.WriteAnnotation(aDocString: string; aIndentation: Integer = 0; aNs: string = 'xs:'); begin Write(Format('<%sannotation>',[aNs]), aIndentation); WriteDocumentation(aDocString,aIndentation+3); Write(Format('',[aNs]), aIndentation); end; procedure TRODLToWSDL.WriteDocumentation(aDocString: string; aIndentation: Integer = 0; aNs: string = 'xs:'); begin Write(Format('<%sdocumentation>',[aNs]), aIndentation); Write(Format('%s', [aDocString]),aIndentation); Write(Format('',[aNs]), aIndentation); end; procedure TRODLToWSDL.WriteService(aLibrary: TRODLLibrary; aService: TRODLService); begin // We only write the service itself, ignoring the anchestors if aService.isPrivate then Exit; Write(Format('', [aService.Name]), 3); WriteAnnotation(aService.Default.Documentation, 6); while Assigned(aService) and not aService.isPrivate do begin Write(Format('', [aService.Name, aService.Name]), 6); Write(Format('', [fLocation]), 9); Write('', 6); aService := NIL;//GetAnchestor(aLibrary, aService); end; Write('',3); end; procedure TRODLToWSDL.WriteStruct(const aLibrary: TRODLLibrary; aStruct: TRODLStruct); var i : integer; begin if fExternalTypesAsReferences and (aStruct.Attributes.Values['ImportedFromUrl'] <> '') then exit; Write(Format('', [aStruct.Name]), 9); WriteAnnotation(aStruct.Documentation, 9); {Giovanni} Write('', 12); while Assigned(aStruct) do begin for i := 0 to aStruct.Count-1 do with aStruct.Items[i] do begin Write(Format('', [Name, ExtSOAPDataType(aLibrary, DataType)]), 15); WriteAnnotation(Documentation, 15); {Giovanni} Write('',15); end; if aStruct.Ancestor <> '' then begin aStruct := aLibrary.FindStruct(aStruct.Ancestor) end else begin aStruct := nil; end; end; Write('', 12); Write('', 9); end; procedure TRODLToWSDL.WriteLiteralParameters(aLibrary: TRODLLibrary; aService: TRODLService); var o, p, i : integer; dups : TStringList; s, svcname, mtdname : string; op : TRODLOperation; begin // Writes all the methods of this service and its anchestors. // If more than one service descend from the same base one, the WSDL has to be generated // using a format like this: http://localhost:8099/SOAP?Service=ServiceOne svcname := aService.Name; dups := TStringList.Create; dups.Duplicates := dupIgnore; dups.Sorted := TRUE; try while Assigned(aService) and not aService.isPrivate do begin for o := 0 to (aService.Default.Count-1) do begin op := aService.Default.Items[o]; // If a method with this name is present, it skips it mtdname := UpperCase(op.Name); if (dups.IndexOf(mtdname)>=0) then Continue else dups.Add(mtdname); s := op.Attributes.Values['SOAPInputName']; if s = '' then s := Format('%s___%s', [svcname, op.Name]); p := 0; for i := 0 to op.Count -1 do begin if op[i].Flag in [fIn, fInOut] then inc(p); end; write(Format('', [s]), 3); if p = 0 then begin write('', 6); end else begin write('', 6); write('', 9); for i := 0 to op.Count -1 do begin if op[i].Flag in [fIn, fInOut] then write(Format('', [op[i].Name, ExtSOAPDataType(aLibrary, op[i].DataType)]), 12); end; write('', 9); write('', 6); end; write('', 3); s := op.Attributes.Values['SOAPOutputName']; if s = '' then s := Format('%s___%sResponse', [svcname, op.Name]); p := 0; for i := 0 to op.Count -1 do begin if op[i].Flag in [fOut, fInOut, fResult] then inc(p); end; if op.Result <> nil then begin inc(p); end; write(Format('', [s]), 3); if p = 0 then begin write('', 6); end else begin write('', 6); write('', 9); for i := 0 to op.Count -1 do begin if op[i].Flag in [fOut, fInOut, fResult] then write(Format('', [op[i].Name, ExtSOAPDataType(aLibrary, op[i].DataType)]), 12); end; if op.Result <> nil then write(Format('', [op.Result.Name, ExtSOAPDataType(aLibrary, op.Result.DataType)]), 12); write('', 9); write('', 6); end; write('', 3); end; aService := GetAnchestor(aLibrary, aService); end; finally dups.Free; end; end; constructor TRODLToWSDL.Create(const aLibraryFile, aTargetEntity: string); begin fTargetNamespace := 'http://tempuri.org/'; fExternalRefs := TStringList.Create; fExternalUrls := TStringList.Create; inherited; end; constructor TRODLToWSDL.Create(const aLibrary: TRODLLibrary; const aTargetEntity: string); begin fTargetNamespace := 'http://tempuri.org/'; fExternalRefs := TStringList.Create; fExternalUrls := TStringList.Create; inherited; end; destructor TRODLToWSDL.Destroy; begin fExternalRefs.Free; fExternalUrls.Free; inherited; end; procedure TRODLToWSDL.AddExternal(aNode: TRODLEntity); begin if aNode.Attributes.Values['ImportedFromUrl'] = '' then exit; if fExternalRefs.IndexOf(aNode.Attributes.Values['ImportedFromNamespace']) <> -1 then exit; fExternalRefs.Add(aNode.Attributes.Values['ImportedFromNamespace']); fExternalUrls.ADd(aNode.Attributes.Values['ImportedFromUrl']); end; function TRODLToWSDL.ExtSOAPDataType(aLibrary: TRODLLibrary; const aDataTypeName: string): string; var el: TRODLEntity; begin if fExternalTypesAsReferences then begin el := aLibrary.FindStruct(aDataTypeName); if el = nil then el := aLibrary.FindEnum(aDataTypeName); if el = nil then el := aLibrary.FindArray(aDataTypeName); if el <> nil then begin if el.Attributes.values['ImportedFromNamespace'] <> '' then begin result := 'ns'+IntToStr(fExternalRefs.IndexOf(el.Attributes.values['ImportedFromNamespace']))+':'+aDataTypeName; exit; end; end; end; result := SOAPDataType(aDataTypeName, True); end; end.