fpopenapi.codegen.pp 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790
  1. {
  2. This file is part of the Free Component Library
  3. Copyright (c) 2024 by Michael Van Canneyt [email protected]
  4. Master Open API code generator
  5. See the file COPYING.FPC, included in this distribution,
  6. for details about the copyright.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  10. **********************************************************************}
  11. unit fpopenapi.codegen;
  12. {$mode ObjFPC}{$H+}
  13. interface
  14. uses
  15. {$IFDEF FPC_DOTTEDUNITS}
  16. System.Classes, System.SysUtils, System.StrUtils, System.DateUtils, Pascal.CodeGenerator, System.IniFiles,
  17. {$ELSE}
  18. Classes, SysUtils, strutils, dateutils, pascodegen, inifiles,
  19. {$ENDIF}
  20. fpjson.schema.types,
  21. fpjson.schema.Pascaltypes,
  22. fpjson.schema.codegen,
  23. fpopenapi.objects,
  24. fpopenapi.types,
  25. fpopenapi.pascaltypes;
  26. Type
  27. TUnitKind = (ukDto, ukSerialize, ukClientServiceIntf, ukServerServiceHandler, ukClientServiceImpl, ukServerServiceImpl, ukClientParent, ukServerParent, ukServerProxy);
  28. const
  29. DefaultUnitSuffix = '.{kind}';
  30. DefaultUnitExtension = '.pas';
  31. DefaultDtoSuffix = 'Dto';
  32. DefaultSerializerSuffix = 'Serializer';
  33. DefaultClientServiceIntfSuffix = 'Service.Intf';
  34. DefaultClientServiceImplSuffix = 'Service.Impl';
  35. DefaultServerServiceHandlerSuffix = 'Module.Handler';
  36. DefaultServerServiceImplSuffix = 'Module.Impl';
  37. DefaultServiceNamePrefix = '';
  38. DefaultServiceNameSuffix = 'Service';
  39. DefaultServerProxyModuleName = 'TServerProxy';
  40. DefaultServerProxyModuleParentName = 'TDataModule';
  41. DefaultServerProxyModuleParentUnit = ''; // Depends on Delphicode or not
  42. DefaultServerProxyUseServiceInterface = True;
  43. Suffixes : Array[TUnitKind] of string = (
  44. DefaultDtoSuffix,
  45. DefaultSerializerSuffix,
  46. DefaultClientServiceIntfSuffix,
  47. DefaultServerServiceHandlerSuffix,
  48. DefaultClientServiceImplSuffix,
  49. DefaultServerServiceImplSuffix,
  50. '',
  51. '',
  52. 'ServerProxy');
  53. type
  54. { TOpenAPICodeGen }
  55. TOpenAPICodeGen = class(TComponent)
  56. private
  57. FAbstractServiceCalls: Boolean;
  58. FAPI: TOpenAPI;
  59. FAsyncService: boolean;
  60. FBaseOutputFileName: string;
  61. FClientParentClass: String;
  62. FDelphiCode: boolean;
  63. FGenerateClient: boolean;
  64. FGenerateServer: boolean;
  65. FGenerateServerProxyModule: Boolean;
  66. FOnLog: TSchemaCodeGenLogEvent;
  67. FParentHasCancelRequest: Boolean;
  68. FServerParentClass: String;
  69. FServerProxyFormFile: Boolean;
  70. FServerProxyModuleName: String;
  71. FServerProxyModuleParentName: String;
  72. FServerProxyModuleParentUnit: String;
  73. FServerProxyUseServiceInterface: Boolean;
  74. FServiceMap: TStrings;
  75. FServiceNamePrefix: String;
  76. FServiceNameSuffix: String;
  77. FSkipServerServiceImplementationModule: Boolean;
  78. FUnitExtension: String;
  79. FUnitSuffix: String;
  80. FUseEnums: boolean;
  81. FUUIDMap: TStrings;
  82. FTypeAliases: TStrings;
  83. FVerboseHeader: boolean;
  84. FUnitNames : Array [TUnitKind] of string;
  85. procedure CleanMaps;
  86. function GetBaseOutputUnitName: string;
  87. function GetServerProxyModuleName: String;
  88. function GetServerProxyModuleParentUnit: String;
  89. function GetUnitName(AIndex: TUnitKind): String;
  90. function GetUnitSuffix(aKind: TUnitKind): String;
  91. procedure SetUnitName(AIndex: TUnitKind; AValue: String);
  92. protected
  93. procedure DoLog(const aType: TEventType; const aMessage: string); virtual;
  94. procedure DoCodeLog(Sender: TObject; LogType: TCodegenLogType; const Msg: string);
  95. procedure DoLog(const aType: TEventType; const aFmt: string; aArgs: array of const);
  96. function ResolveUnit(aKind: TUnitKind; FullPath : Boolean = False): String;
  97. procedure Configure(aCodegen: TJSONSchemaCodeGenerator); virtual;
  98. function CreateAPIData(aAPI: TOpenAPI): TAPIData; virtual;
  99. procedure GenerateRecordDefs(aData: TAPIData); virtual;
  100. procedure GenerateSerializerDefs(aData: TAPIData); virtual;
  101. procedure GenerateServiceInterface(aData: TAPIData); virtual;
  102. procedure GenerateServiceImplementation(aData: TAPIData); virtual;
  103. procedure GenerateServerHandlerModule(aData: TAPIData); virtual;
  104. procedure GenerateServerModuleImplementation(aData: TAPIData); virtual;
  105. procedure GenerateServerProxy(aData: TAPIData); virtual;
  106. procedure GetUUIDMap(aData: TAPIData);
  107. procedure PrepareAPIData(aData: TAPIData); virtual;
  108. public
  109. constructor Create(AOwner: TComponent); override;
  110. destructor Destroy; override;
  111. // Called during create, use to reset.
  112. procedure DefaultSettings;
  113. // Load various properties from ini file.
  114. procedure LoadConfig(aIni: TCustomIniFile; const aSection: String); virtual;
  115. // Load various properties from ini file using the default section.
  116. procedure LoadConfig(aConfigFile: String);
  117. // Write configuration to .ini
  118. procedure SaveConfig(aIni: TCustomIniFile; const aSection: String); virtual;
  119. // Write configuration to file
  120. procedure SaveConfig(aConfigFile: String);
  121. // Generate code.
  122. procedure Execute;
  123. // The OpenAPI description to work with. Set before calling Execute
  124. property API: TOpenAPI read FAPI write FAPI;
  125. // Base unit filename
  126. property BaseOutputFileName: string read FBaseOutputFileName write FBaseOutputFileName;
  127. // Output filename
  128. property BaseOutputUnitName: string read GetBaseOutputUnitName;
  129. // Aliases for types
  130. property TypeAliases: TStrings read FTypeAliases;
  131. // InterfaceName:UUID to reuse UUIDS for interfaces.
  132. property UUIDMap: TStrings read FUUIDMap;
  133. // Map operationId or verb:path to a ServiceName.MethodName pair.
  134. property ServiceMap: TStrings read FServiceMap;
  135. // Generate Dto/Serializer code compilable with Delphi
  136. property DelphiCode: boolean read FDelphiCode write FDelphiCode;
  137. // Write command-line options into header
  138. property VerboseHeader: boolean read FVerboseHeader write FVerboseHeader;
  139. // User enumerateds (default is to use string)
  140. property UseEnums: boolean read FUseEnums write FUseEnums;
  141. // Generate a service implementation
  142. property GenerateServer: boolean read FGenerateServer write FGenerateServer;
  143. // Generate a service implementation
  144. property GenerateClient: boolean read FGenerateClient write FGenerateClient;
  145. // Use async service calls.
  146. property AsyncService : boolean Read FAsyncService Write FAsyncService;
  147. // Diagnostic messages are written to the log
  148. property OnLog: TSchemaCodeGenLogEvent read FOnLog write FOnLog;
  149. // Client Service parent has a cancel request method.
  150. Property ParentHasCancelRequest : Boolean Read FParentHasCancelRequest Write FParentHasCancelRequest;
  151. // How to construct various unit name suffixes: {kind} placeholder. Default is .{Kind};
  152. Property UnitSuffix : String read FUnitSuffix Write FUnitSuffix;
  153. // Extension for unit files.
  154. Property UnitExtension : String Read FUnitExtension Write FUnitExtension;
  155. // Dto definition unit file
  156. Property DtoUnit : String index ukDto Read GetUnitName Write SetUnitName;
  157. // Dto serializer unit file
  158. Property SerializeUnit : String index ukSerialize Read GetUnitName Write SetUnitName;
  159. // Client service interface definition unit name
  160. Property ClientServiceInterfaceUnit : String index ukClientServiceIntf Read GetUnitName Write SetUnitName;
  161. // Server service interface definition unit name
  162. Property ServerServiceInterfaceUnit : String index ukServerServiceHandler Read GetUnitName Write SetUnitName;
  163. // Client service implementation unit name
  164. Property ClientServiceImplementationUnit : String index ukClientServiceImpl Read GetUnitName Write SetUnitName;
  165. // Server service implementation unit name
  166. Property ServerServiceImplementationUnit : String index ukServerServiceImpl Read GetUnitName Write SetUnitName;
  167. // Unit containing Client service parent class
  168. Property ClientServiceParentUnit : String index ukClientParent Read GetUnitName Write SetUnitName;
  169. // Unit containing Server service parent class
  170. Property ServerServiceParentUnit : String index ukServerParent Read GetUnitName Write SetUnitName;
  171. // Client service parent class name
  172. Property ServerServiceParentClass : String Read FServerParentClass Write FServerParentClass;
  173. // Server service parent class name
  174. Property ClientServiceParentClass : String Read FClientParentClass Write FClientParentClass;
  175. // Should the server service implement the methods as abstract ?
  176. Property AbstractServiceCalls : Boolean Read FAbstractServiceCalls Write FAbstractServiceCalls;
  177. // Skip generation of implementation module (only used when AbstractServiceCalls is True
  178. Property SkipServerServiceImplementationModule : Boolean Read FSkipServerServiceImplementationModule Write FSkipServerServiceImplementationModule;
  179. // In case of multiple services modules, generate a "server proxy" TDataModule that contains each service as a property?
  180. Property GenerateServerProxyModule : Boolean Read FGenerateServerProxyModule Write FGenerateServerProxyModule;
  181. // Server proxy unit name serservice parent class name
  182. Property ServerProxyUnit : String index ukServerProxy Read GetUnitName Write SetUnitName;
  183. // Class name for server proxy datamodule.
  184. Property ServerProxyModuleName : String Read GetServerProxyModuleName Write FServerProxyModuleName;
  185. // Class name for server proxy parent class.
  186. Property ServerProxyModuleParentName : String Read FServerProxyModuleParentName Write FServerProxyModuleParentName;
  187. // Unit name where server proxy parent class is defined.
  188. Property ServerProxyModuleParentUnit : String Read GetServerProxyModuleParentUnit Write FServerProxyModuleParentUnit;
  189. // Define service properties using their interface definition.
  190. Property ServerProxyUseServiceInterface : Boolean Read FServerProxyUseServiceInterface Write FServerProxyUseServiceInterface;
  191. // Generate form file for ServerProxy module
  192. Property ServerProxyFormFile : Boolean Read FServerProxyFormFile Write FServerProxyFormFile;
  193. // Prefix for client/server service name
  194. Property ServiceNameSuffix : String Read FServiceNameSuffix Write FServiceNameSuffix;
  195. // Prefix for client/server service name
  196. Property ServiceNamePrefix : String Read FServiceNamePrefix Write FServiceNamePrefix;
  197. // Prefix for client/server service name
  198. end;
  199. implementation
  200. uses fpopenapi.generators;
  201. { TOpenAPICodeGen }
  202. Const
  203. DefaultSection = 'CodeGen';
  204. KeyUnitSuffix = 'UnitSuffix';
  205. KeyUnitExtension = 'UnitExtension';
  206. KeyDTOUnit = 'DtoUnit';
  207. KeySerializeUnit = 'SerializerUnit';
  208. KeyClientServiceInterface = 'ClientServiceInterfaceUnit';
  209. KeyServerServiceInterface = 'ServerServiceInterfaceUnit';
  210. KeyClientServiceImplementation = 'ClientServiceImplementationUnit';
  211. KeyServerServiceImplementation = 'ServerServiceImplementationUnit';
  212. KeyClientParentClass = 'ClientParentClass';
  213. KeyClientParentUnit = 'ClientParentUnit';
  214. KeyServerParentClass = 'ServerParentClass';
  215. KeyServerParentUnit = 'ServerParentUnit';
  216. KeyParentHasCancelRequest = 'ParentHasCancelRequest';
  217. KeyAbstractServiceCalls = 'AbstractServiceCalls';
  218. KeyGenerateServerProxyModule = 'GenerateServerProxyModule';
  219. KeyServiceNameSuffix = 'ServiceNameSuffix';
  220. KeyServiceNamePrefix = 'ServiceNamePrefix';
  221. KeyServerProxyModuleName = 'ServerProxyModuleName';
  222. KeyServerProxyModuleParentName = 'ServerProxyModuleParentName';
  223. KeyServerProxyModuleParentUnit = 'ServerProxyModuleParentUnit';
  224. KeyServerProxyUseServiceInterface = 'ServerProxyModuleUseInterface';
  225. KeyServerProxyFormFile = 'ServerProxyFormFile';
  226. KeyServerProxyUnit = 'ServerProxyUnit' ;
  227. { TOpenAPICodeGen }
  228. constructor TOpenAPICodeGen.Create(AOwner: TComponent);
  229. begin
  230. inherited Create(AOwner);
  231. FTypeAliases := TStringList.Create;
  232. FUUIDMap := TStringList.Create;
  233. FServiceMap := TStringList.Create;
  234. DefaultSettings;
  235. end;
  236. destructor TOpenAPICodeGen.Destroy;
  237. begin
  238. FreeAndNil(FTypeAliases);
  239. FreeAndNil(FUUIDMap);
  240. FreeAndNil(FServiceMap);
  241. inherited Destroy;
  242. end;
  243. procedure TOpenAPICodeGen.DefaultSettings;
  244. var
  245. aKind : TUnitKind;
  246. begin
  247. GenerateServerProxyModule:=False;
  248. GenerateServer:=False;
  249. GenerateClient:=True;
  250. AbstractServiceCalls:=True;
  251. ParentHasCancelRequest:=True;
  252. UnitSuffix:=DefaultUnitSuffix;
  253. UnitExtension:=DefaultUnitExtension;
  254. For aKind in TUnitKind do
  255. FUnitNames[aKind]:='';
  256. ClientServiceParentClass:='TFPOpenAPIServiceClient';
  257. ServerServiceParentClass:='TFPOpenAPIModule';
  258. ClientServiceParentUnit:= 'fpopenapiclient';
  259. ServerServiceParentUnit:='fpopenapimodule';
  260. ServiceNamePrefix:=DefaultServiceNamePrefix;
  261. ServiceNameSuffix:=DefaultServiceNameSuffix;
  262. ServerProxyModuleName:=DefaultServerProxyModuleName;
  263. ServerProxyModuleParentName:=DefaultServerProxyModuleParentName;
  264. ServerProxyModuleParentUnit:=DefaultServerProxyModuleParentUnit;
  265. ServerProxyUseServiceInterface:=DefaultServerProxyUseServiceInterface;
  266. end;
  267. procedure TOpenAPICodeGen.LoadConfig(aIni : TCustomIniFile; const aSection : String);
  268. var
  269. lSection: String;
  270. begin
  271. lSection:=aSection;
  272. if lSection='' then
  273. lSection:=DefaultSection;
  274. with aIni do
  275. begin
  276. UnitSuffix:=ReadString(lSection,KeyUnitSuffix,UnitSuffix);
  277. UnitExtension:=ReadString(lSection,KeyUnitExtension,UnitExtension);
  278. DtoUnit:=ReadString(lSection,KeyDtoUnit,DtoUnit);
  279. SerializeUnit:=ReadString(lSection,KeySerializeUnit,SerializeUnit);
  280. ClientServiceInterfaceUnit:=ReadString(lSection,KeyClientServiceInterface,ClientServiceInterfaceUnit);
  281. ServerServiceInterfaceUnit:=ReadString(lSection,KeyServerServiceInterface,ServerServiceInterfaceUnit);
  282. ClientServiceImplementationUnit:=ReadString(lSection,KeyClientServiceImplementation,ClientServiceImplementationUnit);
  283. ServerServiceImplementationUnit:=ReadString(lSection,KeyServerServiceImplementation,ServerServiceImplementationUnit);
  284. ClientServiceParentClass:=ReadString(lSection,KeyClientParentClass,ClientServiceParentClass);
  285. ClientServiceParentUnit:=ReadString(lSection,KeyClientParentUnit,ClientServiceParentUnit);
  286. ServerServiceParentClass:=ReadString(lSection,KeyServerParentClass,ServerServiceParentClass);
  287. ServerServiceParentUnit:=ReadString(lSection,KeyServerParentUnit,ServerServiceParentUnit);
  288. ParentHasCancelRequest:=ReadBool(lSection,KeyParentHasCancelRequest,ParentHasCancelRequest);
  289. AbstractServiceCalls:=ReadBool(lSection,KeyAbstractServiceCalls,AbstractServiceCalls);
  290. ServiceNameSuffix:=ReadString(lSection,KeyServiceNameSuffix,ServiceNameSuffix);
  291. ServiceNamePrefix:=ReadString(lSection,KeyServiceNamePrefix,ServiceNamePrefix);
  292. GenerateServerProxyModule:=ReadBool(lSection,KeyGenerateServerProxyModule,GenerateServerProxyModule);
  293. ServerProxyModuleName:=ReadString(lSection,KeyServerProxyModuleName,ServerProxyModuleName);
  294. ServerProxyModuleParentName:=ReadString(lSection,KeyServerProxyModuleParentName,ServerProxyModuleParentName);
  295. ServerProxyModuleParentUnit:=ReadString(lSection,KeyServerProxyModuleParentName,ServerProxyModuleParentUnit);
  296. ServerProxyUseServiceInterface:=ReadBool(lSection,KeyServerProxyUseServiceInterface,ServerProxyUseServiceInterface);
  297. ServerProxyUnit:=ReadString(lSection,KeyServerProxyUnit,ServerProxyUnit);
  298. ServerProxyFormFile:=ReadBool(lSection,KeyServerProxyFormFile,ServerProxyFormFile);
  299. end;
  300. end;
  301. procedure TOpenAPICodeGen.LoadConfig(aConfigFile: String);
  302. var
  303. lIni : TMemIniFile;
  304. begin
  305. lIni:=TMemIniFile.Create(aConfigFile);
  306. try
  307. LoadConfig(lIni,'');
  308. finally
  309. lIni.Free;
  310. end;
  311. end;
  312. procedure TOpenAPICodeGen.SaveConfig(aIni : TCustomIniFile; const aSection : String);
  313. var
  314. lSection : String;
  315. begin
  316. lSection:=aSection;
  317. if lSection='' then
  318. lSection:=DefaultSection;
  319. with aIni do
  320. begin
  321. WriteString(lSection,KeyUnitSuffix,UnitSuffix);
  322. WriteString(lSection,KeyUnitExtension,UnitExtension);
  323. WriteString(lSection,KeyDtoUnit,DtoUnit);
  324. WriteString(lSection,KeySerializeUnit,SerializeUnit);
  325. WriteString(lSection,KeyClientServiceInterface,ClientServiceInterfaceUnit);
  326. WriteString(lSection,KeyServerServiceInterface,ServerServiceInterfaceUnit);
  327. WriteString(lSection,KeyClientServiceImplementation,ClientServiceImplementationUnit);
  328. WriteString(lSection,KeyServerServiceImplementation,ServerServiceImplementationUnit);
  329. WriteString(lSection,KeyClientParentClass,ClientServiceParentClass);
  330. WriteString(lSection,KeyClientParentUnit,ClientServiceParentUnit);
  331. WriteString(lSection,KeyServerParentClass,ServerServiceParentClass);
  332. WriteString(lSection,KeyServerParentUnit,ServerServiceParentUnit);
  333. WriteBool(lSection,KeyParentHasCancelRequest,ParentHasCancelRequest);
  334. WriteBool(lSection,KeyAbstractServiceCalls,AbstractServiceCalls);
  335. WriteString(lSection,KeyServiceNameSuffix,ServiceNameSuffix);
  336. WriteString(lSection,KeyServiceNamePrefix,ServiceNamePrefix);
  337. WriteString(lSection,KeyServiceNameSuffix,ServiceNameSuffix);
  338. WriteString(lSection,KeyServerProxyModuleName,ServerProxyModuleName);
  339. WriteString(lSection,KeyServerProxyModuleParentUnit,ServerProxyModuleParentUnit);
  340. WriteString(lSection,KeyServerProxyUnit,ServerProxyUnit);
  341. WriteBool(lSection,KeyServerProxyUseServiceInterface,ServerProxyUseServiceInterface);
  342. WriteBool(lSection,KeyServerProxyFormFile,ServerProxyFormFile);
  343. WriteBool(lSection,KeyGenerateServerProxyModule, GenerateServerProxyModule);
  344. end;
  345. end;
  346. procedure TOpenAPICodeGen.SaveConfig(aConfigFile: String);
  347. var
  348. lIni : TMemIniFile;
  349. begin
  350. lIni:=TMemIniFile.Create(aConfigFile);
  351. try
  352. SaveConfig(lIni,'');
  353. lIni.UpdateFile;
  354. finally
  355. lIni.Free;
  356. end;
  357. end;
  358. procedure TOpenAPICodeGen.DoCodeLog(Sender: TObject; LogType: TCodegenLogType;
  359. const Msg: string);
  360. begin
  361. if LogType = cltInfo then
  362. DoLog(etInfo, Msg)
  363. else
  364. DoLog(etDebug, Msg);
  365. end;
  366. function TOpenAPICodeGen.GetUnitSuffix (aKind : TUnitKind) : String;
  367. var
  368. lSuff : String;
  369. begin
  370. lSuff:=UnitSuffix;
  371. if lSuff='' then
  372. lSuff:=DefaultUnitSuffix;
  373. Result:=StringReplace(lSuff,'{kind}',Suffixes[aKind],[]);
  374. end;
  375. function TOpenAPICodeGen.ResolveUnit(aKind: TUnitKind; FullPath: Boolean): String;
  376. begin
  377. Result := FUnitNames[aKind];
  378. if Result = '' then
  379. Result := BaseOutputUnitName + GetUnitSuffix(aKind);
  380. if FullPath then
  381. Result:=ExtractFilePath(BaseOutputFileName)+Result+UnitExtension;
  382. end;
  383. function TOpenAPICodeGen.GetBaseOutputUnitName: string;
  384. begin
  385. Result := ExtractFileName(BaseOutputFileName);
  386. end;
  387. function TOpenAPICodeGen.GetServerProxyModuleName: String;
  388. begin
  389. Result:=FServerProxyModuleName;
  390. if Result='' then
  391. Result:='TServerProxy';
  392. end;
  393. function TOpenAPICodeGen.GetServerProxyModuleParentUnit: String;
  394. begin
  395. Result:=FServerProxyModuleParentUnit;
  396. if Result='' then
  397. if DelphiCode then
  398. Result:='System.Classes'
  399. else
  400. Result:='Classes';
  401. end;
  402. function TOpenAPICodeGen.GetUnitName(AIndex: TUnitKind): String;
  403. begin
  404. Result:=FUnitNames[aIndex];
  405. if Result='' then
  406. end;
  407. procedure TOpenAPICodeGen.SetUnitName(AIndex: TUnitKind; AValue: String);
  408. begin
  409. FUnitNames[aIndex]:=aValue;
  410. end;
  411. procedure TOpenAPICodeGen.DoLog(const aType: TEventType; const aMessage: string);
  412. begin
  413. if Assigned(FOnLog) then
  414. FOnLog(aType, aMessage);
  415. end;
  416. procedure TOpenAPICodeGen.DoLog(const aType: TEventType; const aFmt: string;
  417. aArgs: array of const);
  418. begin
  419. if Assigned(FOnLog) then
  420. FOnLog(aType, Format(aFmt, aArgs));
  421. end;
  422. function TOpenAPICodeGen.CreateAPIData(aAPI: TOpenAPI): TAPIData;
  423. begin
  424. Result := TAPIData.Create(aAPI);
  425. end;
  426. procedure TOpenAPICodeGen.CleanMaps;
  427. procedure CleanMap(aMap: TStrings);
  428. var
  429. I, P: integer;
  430. S: string;
  431. begin
  432. for I := aMap.Count - 1 downto 0 do
  433. begin
  434. S := aMap[I];
  435. P := Pos('#', S);
  436. if P > 0 then
  437. begin
  438. S := Trim(Copy(S, 1, P - 1));
  439. if S <> '' then
  440. aMap[I] := S
  441. else
  442. aMap.Delete(I);
  443. end;
  444. end;
  445. end;
  446. begin
  447. CleanMap(FUUIDMap);
  448. CleanMap(FServiceMap);
  449. end;
  450. procedure TOpenAPICodeGen.PrepareAPIData(aData: TAPIData);
  451. var
  452. I: integer;
  453. N, A: string;
  454. begin
  455. for I := 0 to FTypeAliases.Count - 1 do
  456. begin
  457. FTypeAliases.GetNameValue(I, N, A);
  458. if (N <> '') and (A <> '') then
  459. aData.AddAliasToTypeMap(ptSchemaStruct, A, N, A, nil);
  460. end;
  461. CleanMaps;
  462. aData.UseEnums := Self.UseEnums;
  463. aData.CreateDefaultTypeMaps;
  464. aData.CreateDefaultAPITypeMaps(Self.GenerateServer);
  465. aData.VoidResultCallbackType:='TVoidResultCallBack';
  466. if FServiceMap.Count > 0 then
  467. aData.RecordMethodNameMap(FServiceMap);
  468. aData.CreateServiceDefs;
  469. if (FUUIDMap.Count > 0) then
  470. aData.ApplyUUIDMap(FUUIDMap);
  471. DoLog(etInfo, 'Found %d Dto types', [aData.APITypeCount]);
  472. DoLog(etInfo, 'Created %d services', [aData.ServiceCount]);
  473. end;
  474. procedure TOpenAPICodeGen.GetUUIDMap(aData: TAPIData);
  475. var
  476. lType: TAPITypeData;
  477. lService: TAPIService;
  478. I: integer;
  479. begin
  480. for I := 0 to aData.APITypeCount - 1 do
  481. begin
  482. lType := aData.APITypes[I];
  483. FUUIDMap.Values[lType.SchemaName] := lType.InterfaceUUID;
  484. end;
  485. for I := 0 to aData.ServiceCount - 1 do
  486. begin
  487. lService := aData.Services[I];
  488. FUUIDMap.Values[lService.ServiceName] := lService.ServiceUUID;
  489. end;
  490. end;
  491. procedure TOpenAPICodeGen.Execute;
  492. var
  493. lAPIData: TAPIData;
  494. begin
  495. if not assigned(FAPI) then
  496. Raise EGenAPI.Create('API not set');
  497. lAPIData := CreateAPIData(FAPI);
  498. try
  499. lAPIData.OnLog := Self.OnLog;
  500. lAPIData.DelphiTypes := Self.DelphiCode;
  501. lAPIData.ServiceNamePrefix := ServiceNamePrefix;
  502. lAPIData.ServiceNameSuffix := ServiceNameSuffix;
  503. PrepareAPIData(lAPIData);
  504. GenerateRecordDefs(lAPIData);
  505. GenerateSerializerDefs(lAPIData);
  506. if GenerateClient then
  507. begin
  508. GenerateServiceInterface(lAPIData);
  509. GenerateServiceImplementation(lAPIData);
  510. end;
  511. if GenerateServer then
  512. begin
  513. GenerateServerHandlerModule(lAPIData);
  514. if AbstractServiceCalls and not SkipServerServiceImplementationModule then
  515. GenerateServerModuleImplementation(lAPIData);
  516. end;
  517. if GenerateServerProxyModule then
  518. GenerateServerProxy(lAPIData);
  519. GetUUIDMap(lAPIData);
  520. finally
  521. lAPIData.Free;
  522. end;
  523. end;
  524. procedure TOpenAPICodeGen.Configure(aCodegen: TJSONSchemaCodeGenerator);
  525. begin
  526. acodegen.OnLog := @DoCodeLog;
  527. acodegen.DelphiCode := Self.DelphiCode;
  528. acodegen.VerboseHeader := Self.VerboseHeader;
  529. acodegen.WriteClassType := True;
  530. if acodegen is TOpenAPIServiceCodeGen then
  531. TOpenAPIServiceCodeGen(aCodegen).AsyncService:=Self.AsyncService
  532. end;
  533. procedure TOpenAPICodeGen.GenerateRecordDefs(aData: TAPIData);
  534. var
  535. codegen: TDtoCodeGen;
  536. lFileName : String;
  537. begin
  538. lFileName:=ResolveUnit(ukDto,True);
  539. DoLog(etInfo, 'Writing Dto definitions to file "%s"', [lFileName]);
  540. codegen := TDtoCodeGen.Create(Self);
  541. try
  542. Configure(codegen);
  543. codegen.OutputUnitName := ResolveUnit(ukDto);
  544. codegen.Execute(aData);
  545. codegen.Source.SaveToFile(lFileName);
  546. finally
  547. codegen.Free;
  548. end;
  549. end;
  550. procedure TOpenAPICodeGen.GenerateSerializerDefs(aData: TAPIData);
  551. var
  552. codegen: TSerializerCodeGen;
  553. lFileName : String;
  554. begin
  555. lFileName:=ResolveUnit(ukSerialize,True);
  556. DoLog(etInfo, 'Writing serialize helpers to file "%s"', [lFileName]);
  557. codegen := TSerializerCodeGen.Create(Self);
  558. try
  559. Configure(codegen);
  560. codegen.OutputUnitName := ResolveUnit(ukSerialize);
  561. codegen.DataUnitName := ResolveUnit(ukDto);
  562. codegen.Execute(aData);
  563. codegen.Source.SaveToFile(lFileName);
  564. finally
  565. codegen.Free;
  566. end;
  567. end;
  568. procedure TOpenAPICodeGen.GenerateServiceInterface(aData: TAPIData);
  569. var
  570. codegen: TServiceInterfaceCodeGen;
  571. lFileName : String;
  572. begin
  573. lFileName:=ResolveUnit(ukClientServiceIntf,True);
  574. DoLog(etInfo, 'Writing service interface to file "%s"', [lFileName]);
  575. codegen := TServiceInterfaceCodeGen.Create(Self);
  576. try
  577. Configure(codegen);
  578. codegen.OutputUnitName := ResolveUnit(ukClientServiceIntf);
  579. codegen.DtoUnit := ResolveUnit(ukDto);
  580. codegen.Execute(aData);
  581. codegen.Source.SaveToFile(lFileName);
  582. finally
  583. codegen.Free;
  584. end;
  585. end;
  586. procedure TOpenAPICodeGen.GenerateServiceImplementation(aData: TAPIData);
  587. var
  588. codegen: TServiceImplementationCodeGen;
  589. lFileName : String;
  590. begin
  591. lFileName:=ResolveUnit(ukClientServiceImpl,True);
  592. DoLog(etInfo, 'Writing service implementation to file "%s"', [lFileName]);
  593. codegen := TServiceImplementationCodeGen.Create(Self);
  594. try
  595. Configure(codegen);
  596. codegen.OutputUnitName := ResolveUnit(ukClientServiceImpl);
  597. codegen.DtoUnit := ResolveUnit(ukDto);
  598. codegen.SerializerUnit := ResolveUnit(ukSerialize);
  599. codegen.ServiceParentClass := ClientServiceParentClass;
  600. codegen.ServiceParentUnit := ClientServiceParentUnit;
  601. codegen.ServiceInterfaceUnit := ResolveUnit(ukClientServiceIntf);
  602. codegen.ParentHasCancelRequest:=Self.ParentHasCancelRequest;
  603. codegen.Execute(aData);
  604. codegen.Source.SaveToFile(lFileName);
  605. finally
  606. codegen.Free;
  607. end;
  608. end;
  609. procedure TOpenAPICodeGen.GenerateServerHandlerModule(aData: TAPIData);
  610. var
  611. codegen: TServerModuleHandlerCodeGen;
  612. lFileName : string;
  613. lKind : TUnitKind;
  614. begin
  615. if Self.AbstractServiceCalls then
  616. lKind:=ukServerServiceHandler
  617. else
  618. lKind:=ukServerServiceImpl;
  619. lFileName:=ResolveUnit(lKind,True);
  620. DoLog(etInfo, 'Writing server HTTP handler module implementation to file "%s"', [lFileName]);
  621. codegen := TServerModuleHandlerCodeGen.Create(Self);
  622. try
  623. Configure(codegen);
  624. codegen.OutputUnitName := ResolveUnit(lKind);
  625. codegen.DtoUnit := ResolveUnit(ukDto);
  626. codegen.SerializerUnit := ResolveUnit(ukSerialize);
  627. codegen.ModuleParentClass := ServerServiceParentClass;
  628. codegen.AbstractServiceCalls := Self.AbstractServiceCalls;
  629. codegen.ModuleParentUnit := ServerServiceParentUnit;
  630. codegen.Execute(aData);
  631. codegen.Source.SaveToFile(lFileName);
  632. finally
  633. codegen.Free;
  634. end;
  635. end;
  636. procedure TOpenAPICodeGen.GenerateServerModuleImplementation(aData: TAPIData);
  637. var
  638. codegen: TServerImplementationModuleCodeGen;
  639. lFileName : string;
  640. begin
  641. lFileName:=ResolveUnit(ukServerServiceImpl,True);
  642. DoLog(etInfo, 'Writing server HTTP module implementation to file "%s"', [lFileName]);
  643. codegen := TServerImplementationModuleCodeGen.Create(Self);
  644. try
  645. Configure(codegen);
  646. codegen.OutputUnitName := ResolveUnit(ukServerServiceImpl);
  647. codegen.DtoUnit := ResolveUnit(ukDto);
  648. codegen.SerializerUnit := ResolveUnit(ukSerialize);
  649. codegen.ModuleParentUnit := ResolveUnit(ukServerServiceHandler);
  650. codegen.Execute(aData);
  651. codegen.Source.SaveToFile(lFileName);
  652. finally
  653. codegen.Free;
  654. end;
  655. end;
  656. procedure TOpenAPICodeGen.GenerateServerProxy(aData: TAPIData);
  657. var
  658. codegen: TServerProxyServiceModuleCodeGen;
  659. lFileName : string;
  660. begin
  661. lFileName:=ResolveUnit(ukServerProxy,True);
  662. DoLog(etInfo, 'Writing server proxy module implementation to file "%s"', [lFileName]);
  663. codegen := TServerProxyServiceModuleCodeGen.Create(Self);
  664. try
  665. Configure(codegen);
  666. codegen.OutputUnitName := ResolveUnit(ukServerProxy);
  667. codegen.ProxyParentClass := ServerProxyModuleParentName;
  668. codegen.ProxyParentUnit := ServerProxyModuleParentUnit;
  669. codegen.ProxyClassName := ServerProxyModuleName;
  670. codegen.UseInterfaceType:=ServerProxyUseServiceInterface;
  671. codegen.ServiceImplementationUnit := ResolveUnit(ukClientServiceImpl);
  672. codegen.ServiceInterfaceUnit := ResolveUnit(ukClientServiceIntf);
  673. codegen.FormFile:=FServerProxyFormFile;
  674. codegen.Execute(aData);
  675. codegen.Source.SaveToFile(lFileName);
  676. if codegen.FormFile then
  677. codegen.Form.SaveToFile(ChangeFileExt(lFileName,'.lfm'));
  678. finally
  679. codegen.Free;
  680. end;
  681. end;
  682. end.