googleservice.pp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588
  1. { **********************************************************************
  2. This file is part of the Free Component Library (FCL)
  3. Copyright (c) 2015 The free pascal team.
  4. Base Google service API classes
  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 googleservice;
  12. {$mode objfpc}{$H+}
  13. interface
  14. uses
  15. Classes, SysUtils, contnrs, restbase, googlebase, fpwebclient, fpjson, googleclient;
  16. Type
  17. TGoogleAPI = Class;
  18. TGoogleAPIClass = Class of TGoogleAPI;
  19. TGoogleAPIArray = Array of TGoogleAPI;
  20. TGoogleResource = Class;
  21. TGoogleResourceClass = Class of TGoogleResource;
  22. TGoogleResourceArray = Array of TGoogleResource;
  23. TGoogleAPIFactory = Class;
  24. TGoogleAPIFactoryClass = Class of TGoogleAPIFactory;
  25. { TGoogleAPI }
  26. TScopeInfo = Record
  27. Name : string;
  28. Description : string;
  29. end;
  30. TScopeInfoArray = Array of TScopeInfo;
  31. TAPIInfo = Record
  32. Name : string;
  33. Version : String;
  34. Revision : string;
  35. id : string;
  36. title : String;
  37. description : string;
  38. ownerDomain : String;
  39. ownerName : String;
  40. icon16 : String;
  41. icon32 : String;
  42. documentationLink : String;
  43. rootUrl : string;
  44. basePath : string;
  45. baseURL : String;
  46. Protocol : string;
  47. servicePath : string;
  48. batchPath : String;
  49. AuthScopes : TScopeInfoArray;
  50. end;
  51. TGoogleAPI = Class(TComponent)
  52. private
  53. FGoogleClient: TGoogleClient;
  54. procedure SetGoogleClient(AValue: TGoogleClient);
  55. Protected
  56. Procedure Notification(AComponent: TComponent; Operation: TOperation); override;
  57. Function API : TGoogleAPI;// Used when creating resources.
  58. Public
  59. // All info in one fell swoop
  60. Class Function APIInfo : TAPIInfo; virtual;
  61. Class Function APIName : String; virtual;
  62. Class Function APIVersion : String; virtual; abstract;
  63. Class Function APIRevision : String; virtual; abstract;
  64. Class Function APIID : String; virtual; abstract;
  65. Class Function APITitle : String; virtual; abstract;
  66. Class Function APIDescription : String; virtual; abstract;
  67. Class Function APIOwnerDomain : String; virtual; abstract;
  68. Class Function APIOwnerName : String; virtual; abstract;
  69. Class Function APIIcon16 : String; virtual; abstract;
  70. Class Function APIIcon32 : String; virtual; abstract;
  71. Class Function APIdocumentationLink : String; virtual; abstract;
  72. Class Function APIrootUrl : string; virtual; abstract;
  73. Class Function APIbasePath : string;virtual; abstract;
  74. Class Function APIbaseURL : String;virtual; abstract;
  75. Class Function APIProtocol : string;virtual; abstract;
  76. Class Function APIservicePath : string;virtual; abstract;
  77. Class Function APIbatchPath : String;virtual; abstract;
  78. Class Function APIAuthScopes : TScopeInfoArray;virtual; abstract;
  79. Class Function APINeedsAuth : Boolean ;virtual;
  80. Class Procedure RegisterAPI; virtual;
  81. Class Procedure RegisterAPIResources; virtual;
  82. Function ServiceCall(Const AResource : TGoogleResource; AMethod, APath, AQuery : String; AInput : TGoogleBaseObject; AReturnClass : TGoogleBaseObjectClass) : TGoogleBaseObject; virtual;
  83. Function ServiceCall(Const AResource : TGoogleResource; AMethod, APath, AQuery, AInput : String) : String; virtual;
  84. Function SubstitutePath(Const AResource,APath : String; Const Args : Array of const) : String;virtual;
  85. Function CreateResource(AClass : TGoogleResourceClass) : TGoogleResource; virtual;
  86. Function CreateResource(const Resource : String) : TGoogleResource; virtual;
  87. Published
  88. Property GoogleClient : TGoogleClient Read FGoogleClient Write SetGoogleClient;
  89. end;
  90. { TGoogleResource }
  91. TGoogleResource = Class(TComponent)
  92. private
  93. FAPI: TGoogleAPI;
  94. Procedure SetAPI(AAPI : TGoogleAPI);
  95. Protected
  96. Procedure CheckAPI;
  97. Procedure Notification(AComponent: TComponent; Operation: TOperation); override;
  98. Public
  99. Class Procedure AddToQuery(Var Q : String; Const AName , AValue : String);virtual;
  100. Class Procedure AddToQuery(Var Q : String; Const AName : String; AValue : Int64);virtual;
  101. Class Procedure AddToQuery(Var Q : String; Const AName : String; AValue : TDateTime);virtual;
  102. Class Procedure AddToQuery(Var Q : String; Const AName : String; AValue : Boolean);virtual;
  103. Function SubstitutePath(Const APath : String; Const Args : Array of const): String;
  104. Function ServiceCall(Const AMethod, APath, AQuery: String; AInput: TGoogleBaseObject; AReturnClass: TGoogleBaseObjectClass): TGoogleBaseObject; virtual;
  105. PubliC
  106. Class Function ResourceName : String; virtual;
  107. Class Function DefaultAPI : TGoogleAPIClass; virtual;
  108. Property API : TGoogleAPI Read FAPI Write SetAPI;
  109. end;
  110. { TGoogleAPIFactory }
  111. TGoogleAPIFactory = Class(TComponent)
  112. Private
  113. FAPIs : TClassList;
  114. FResources : TClassList;
  115. function GetA(AIndex : Integer): TGoogleAPIClass;
  116. function GetACount: Integer;
  117. function GetR(AIndex : Integer): TGoogleResourceClass;
  118. function GetRCount: Integer;
  119. Public
  120. Class var
  121. DefaultFactoryClass : TGoogleAPIFactoryClass;
  122. DefaultFactory : TGoogleAPIFactory;
  123. Public
  124. Constructor Create(Aowner : TComponent); override;
  125. Destructor Destroy; override;
  126. // Resource methods
  127. Procedure RegisterResource(Resource : TGoogleResourceClass); virtual;
  128. Function IndexOfResource(Const Resource : String) : Integer;
  129. Function FindResourceClass(Const Resource : String) : TGoogleResourceClass; virtual;
  130. Function GetResourceClass(Const Resource : String) : TGoogleResourceClass;
  131. Property ResourceClass[AIndex : Integer] : TGoogleResourceClass Read GetR;
  132. Property ResourceCount : Integer Read GetRCount;
  133. // API methods
  134. Procedure RegisterAPI(AAPI : TGoogleAPIClass); virtual;
  135. Function IndexOfAPI(Const API : String) : Integer;
  136. Function FindAPIClass(Const API : String) : TGoogleAPIClass; virtual;
  137. Function GetAPIClass(Const API : String) : TGoogleAPIClass;
  138. Property APIClass[AIndex : Integer] :TGoogleAPIClass Read GetA;
  139. Property APICount : Integer Read GetACount;
  140. end;
  141. Function APIFactory : TGoogleAPIFactory;
  142. implementation
  143. uses httpdefs;
  144. Function APIFactory : TGoogleAPIFactory;
  145. Var
  146. AClass : TGoogleAPIFactoryClass;
  147. begin
  148. If TGoogleAPIFactory.DefaultFactory=Nil then
  149. begin
  150. AClass:=TGoogleAPIFactory.DefaultFactoryClass;
  151. If AClass=Nil then
  152. AClass:=TGoogleAPIFactory;
  153. TGoogleAPIFactory.DefaultFactory:=AClass.Create(Nil);
  154. end;
  155. Result:=TGoogleAPIFactory.DefaultFactory;
  156. end;
  157. { TGoogleAPIFactory }
  158. function TGoogleAPIFactory.GetR(AIndex : Integer): TGoogleResourceClass;
  159. begin
  160. Result:=TGoogleResourceClass(FResources[Aindex]);
  161. end;
  162. function TGoogleAPIFactory.GetA(AIndex : Integer): TGoogleAPIClass;
  163. begin
  164. Result:=TGoogleAPIClass(FAPIs[AIndex])
  165. end;
  166. function TGoogleAPIFactory.GetACount: Integer;
  167. begin
  168. Result:=FAPIS.Count;
  169. end;
  170. function TGoogleAPIFactory.GetRCount: Integer;
  171. begin
  172. Result:=FResources.Count;
  173. end;
  174. Constructor TGoogleAPIFactory.Create(Aowner: TComponent);
  175. begin
  176. inherited Create(Aowner);
  177. FAPIs:=TClassList.Create;
  178. FResources:=TClassList.Create;
  179. end;
  180. Destructor TGoogleAPIFactory.Destroy;
  181. begin
  182. FreeAndNil(FAPIs);
  183. FreeAndNil(FResources);
  184. inherited Destroy;
  185. end;
  186. Procedure TGoogleAPIFactory.RegisterAPI(AAPI: TGoogleAPIClass);
  187. begin
  188. FAPIs.Add(AAPI);
  189. end;
  190. Function TGoogleAPIFactory.IndexOfAPI(Const API: String): Integer;
  191. begin
  192. Result:=FAPIs.Count-1;
  193. While (Result>=0) and (CompareText(TGoogleAPIClass(FAPIs[Result]).APIName,API)<>0) do
  194. Dec(Result);
  195. end;
  196. Function TGoogleAPIFactory.FindAPIClass(Const API: String): TGoogleAPIClass;
  197. Var
  198. I : Integer;
  199. begin
  200. I:=IndexOfAPI(API);
  201. if I=-1 then
  202. Result:=Nil
  203. else
  204. Result:=GetA(I);
  205. end;
  206. Function TGoogleAPIFactory.GetAPIClass(Const API: String): TGoogleAPIClass;
  207. begin
  208. Result:=FindAPIClass(API);
  209. if Result=Nil then
  210. Raise EGoogleAPI.CreateFmt('Unknown API : "%s"',[API]);
  211. end;
  212. Procedure TGoogleAPIFactory.RegisterResource(Resource: TGoogleResourceClass);
  213. begin
  214. FResourceS.Add(Resource);
  215. end;
  216. Function TGoogleAPIFactory.IndexOfResource(Const Resource: String): Integer;
  217. begin
  218. Result:=FResources.Count-1;
  219. While (Result>=0) and (CompareText(TGoogleResourceClass(FResources[Result]).ResourceName,Resource)<>0) do
  220. Dec(Result);
  221. end;
  222. Function TGoogleAPIFactory.FindResourceClass(Const Resource: String): TGoogleResourceClass;
  223. Var
  224. I : Integer;
  225. begin
  226. I:=IndexOfResource(Resource);
  227. if I=-1 then
  228. Result:=Nil
  229. else
  230. Result:=GetR(I);
  231. end;
  232. Function TGoogleAPIFactory.GetResourceClass(Const Resource: String): TGoogleResourceClass;
  233. begin
  234. Result:=FindResourceClass(Resource);
  235. if Result=Nil then
  236. Raise EGoogleAPI.CreateFmt('Unknown resource : "%s"',[Resource]);
  237. end;
  238. { TGoogleResource }
  239. Procedure TGoogleResource.CheckAPI;
  240. begin
  241. If (API=nil) then
  242. Raise EGoogleAPI.Create('Cannot perform this method, API is not assigned');
  243. end;
  244. Procedure TGoogleResource.Notification(AComponent: TComponent; Operation: TOperation
  245. );
  246. begin
  247. inherited Notification(AComponent, Operation);
  248. If Operation=opRemove then
  249. if FAPI=AComponent then
  250. FAPI:=Nil;
  251. end;
  252. Procedure TGoogleResource.SetAPI(AAPI: TGoogleAPI);
  253. begin
  254. If Assigned(FAPI) then
  255. FAPI.RemoveFreeNotification(Self);
  256. FAPI:=AAPI;
  257. If Assigned(FAPI) then
  258. FAPI.FreeNotification(Self);
  259. end;
  260. Class Procedure TGoogleResource.AddToQuery(Var Q: String; Const AName,AValue: String);
  261. begin
  262. If AValue='' then
  263. exit;
  264. if (Q<>'') then
  265. Q:=Q+'&';
  266. Q:=Q+Aname+'='+HTTPEncode(AValue);
  267. end;
  268. Class Procedure TGoogleResource.AddToQuery(Var Q: String; Const AName : String; AValue: Int64);
  269. begin
  270. if AValue=0 then exit;
  271. if (Q<>'') then
  272. Q:=Q+'&';
  273. Q:=Q+Aname+'='+IntToStr(AValue);
  274. end;
  275. Class Procedure TGoogleResource.AddToQuery(Var Q: String; Const AName : String; AValue: TDateTime);
  276. begin
  277. if AValue=0 then exit;
  278. if (Q<>'') then
  279. Q:=Q+'&';
  280. Q:=Q+Aname+'='+DateTimeToRFC3339(AValue);
  281. end;
  282. Class Procedure TGoogleResource.AddToQuery(Var Q: String; Const AName : String; AValue: Boolean);
  283. begin
  284. if (Q<>'') then
  285. Q:=Q+'&';
  286. Q:=Q+Aname+'='+BoolToStr(AValue,'true','false');
  287. end;
  288. Function TGoogleResource.SubstitutePath(Const APath: String;
  289. Const Args: Array of const): String;
  290. begin
  291. CheckAPI;
  292. Result:=API.SubstitutePath(ResourceName,APath,Args);
  293. end;
  294. Function TGoogleResource.ServiceCall(Const AMethod, APath, AQuery: String;
  295. AInput: TGoogleBaseObject; AReturnClass: TGoogleBaseObjectClass): TGoogleBaseObject;
  296. begin
  297. CheckAPI;
  298. Result:=API.ServiceCall(Self,AMethod,APath,AQuery,AInput,AReturnClass);
  299. end;
  300. Class Function TGoogleResource.ResourceName: String;
  301. begin
  302. Result:=ClassName;
  303. if UpCase(Result[1])='T' then
  304. Delete(Result,1,1);
  305. If CompareText(Copy(Result,Length(Result)-7,8),'Resource')=0 then
  306. Result:=Copy(Result,1,Length(Result)-8);
  307. end;
  308. Class Function TGoogleResource.DefaultAPI: TGoogleAPIClass;
  309. begin
  310. Result:=Nil;
  311. end;
  312. { TGoogleAPI }
  313. Class Function TGoogleAPI.APIName: String;
  314. begin
  315. Result:=ClassName;
  316. if UpCase(Result[1])='T' then
  317. Delete(Result,1,1);
  318. If CompareText(Copy(Result,Length(Result)-6,7),'API')=0 then
  319. Result:=Copy(Result,1,Length(Result)-7);
  320. end;
  321. Class Function TGoogleAPI.APINeedsAuth: Boolean;
  322. begin
  323. Result:=Length(APIAuthScopes)<>0;
  324. end;
  325. procedure TGoogleAPI.SetGoogleClient(AValue: TGoogleClient);
  326. begin
  327. if FGoogleClient=AValue then Exit;
  328. If Assigned(FGoogleClient) then
  329. FGoogleClient.RemoveFreeNotification(Self);
  330. FGoogleClient:=AValue;
  331. If Assigned(FGoogleClient) then
  332. FGoogleClient.FreeNotification(Self);
  333. end;
  334. Procedure TGoogleAPI.Notification(AComponent: TComponent; Operation: TOperation
  335. );
  336. begin
  337. inherited Notification(AComponent, Operation);
  338. if (Operation=opRemove) and (AComponent=FGoogleClient) then
  339. FGoogleClient:=Nil;
  340. end;
  341. Function TGoogleAPI.API: TGoogleAPI;
  342. begin
  343. Result:=Self;
  344. end;
  345. Class Function TGoogleAPI.APIInfo: TAPIInfo;
  346. begin
  347. Result.Name:=APIName;
  348. Result.Version:=APIVersion;
  349. Result.Revision:=APIRevision;
  350. Result.ID:=APIID;
  351. Result.Title:=APITitle;
  352. Result.Description:=APIDescription;
  353. Result.OwnerDomain:=APIOwnerDomain;
  354. Result.OwnerName:=APIOwnerName;
  355. Result.Icon16:=APIIcon16;
  356. Result.Icon32:=APIIcon32;
  357. Result.documentationLink:=APIdocumentationLink;
  358. Result.rootUrl:=APIrootUrl;
  359. Result.basePath:=APIbasePath;
  360. Result.baseURL:=APIbaseURL;
  361. Result.Protocol:=APIProtocol;
  362. Result.servicePath:=APIservicePath;
  363. Result.batchPath:=APIbatchPath;
  364. Result.AuthScopes:=APIAuthScopes;
  365. end;
  366. Class Procedure TGoogleAPI.RegisterAPI;
  367. begin
  368. APIFactory.RegisterAPI(Self);
  369. end;
  370. Class Procedure TGoogleAPI.RegisterAPIResources;
  371. begin
  372. // needs to be implemented in descendents
  373. end;
  374. Function TGoogleAPI.ServiceCall(Const AResource: TGoogleResource; AMethod,
  375. APath, AQuery: String; AInput: TGoogleBaseObject;
  376. AReturnClass: TGoogleBaseObjectClass): TGoogleBaseObject;
  377. Var
  378. D : TJSONData;
  379. R,S : String;
  380. C : TGoogleBaseObjectClass;
  381. BC : TBaseObjectClass;
  382. begin
  383. Result:=Nil;
  384. if Assigned(AInput) then
  385. begin
  386. D:=TJSONObject.Create;
  387. AInput.SaveToJSON(TJSONObject(D));
  388. try
  389. S:=D.AsJSON;
  390. finally
  391. D.Free;
  392. end;
  393. end
  394. else
  395. S:='';
  396. R:=ServiceCall(AResource,AMethod,APAth,AQuery,S);
  397. if (R<>'') then
  398. begin
  399. D:=GetJSON(R);
  400. try
  401. C:=Nil;
  402. if Assigned(D) and (D.JSONType=jtObject) then
  403. begin
  404. S:=TJSONObject(D).Get('kind','');
  405. if (S<>'') then
  406. begin
  407. BC:=GoogleFactory.GetObjectClass(s);
  408. If BC.InheritsFrom(TGoogleBaseObject) then
  409. C:=TGoogleBaseObjectClass(BC)
  410. else
  411. C:=Nil;
  412. end;
  413. end;
  414. if C=Nil then
  415. C:=AReturnClass;
  416. Result:=C.Create;
  417. try
  418. Result.LoadFromJSON(D as TJSONObject);
  419. except
  420. FreeAndNil(Result);
  421. Raise;
  422. end;
  423. finally
  424. D.Free;
  425. end;
  426. end;
  427. end;
  428. Function TGoogleAPI.ServiceCall(Const AResource: TGoogleResource; AMethod,
  429. APath, AQuery, AInput: String): String;
  430. Var
  431. URL : String;
  432. Req : TWebClientRequest;
  433. Resp : TWebClientResponse;
  434. begin
  435. URL:=APIBaseURL+APath;
  436. if AQuery<>'' then
  437. URL:=URL+'?'+AQuery;
  438. Result:='';
  439. Req:=Nil;
  440. Resp:=Nil;
  441. try
  442. Req:=googleclient.WebClient.CreateRequest;
  443. if (AInput<>'') then
  444. begin
  445. Req.Headers.Values['Content-type']:='application/json';
  446. Req.SetContentFromString(AInput);
  447. end;
  448. If Not APINeedsAuth then
  449. Resp:=googleclient.WebClient.ExecuteRequest(AMethod,URL,Req)
  450. else
  451. Resp:=googleclient.WebClient.ExecuteSignedRequest(AMethod,URL,Req);
  452. If (Resp.StatusCode div 100)<>2 then
  453. Raise EGoogleAPI.CreateFmt('%d error executing request : %s',[Resp.StatusCode,Resp.StatusText]);
  454. Result:=Resp.GetContentAsString;
  455. finally
  456. Req.Free;
  457. Resp.Free;
  458. end;
  459. end;
  460. Function TGoogleAPI.SubstitutePath(Const AResource, APath: String;
  461. Const Args: Array of const): String;
  462. Var
  463. N,V : String;
  464. I : Integer;
  465. begin
  466. Result:=APath;
  467. I:=0;
  468. While I<High(Args) do
  469. begin
  470. if Args[i].VType<>vtAnsiString then
  471. Raise EGoogleAPI.CreateFmt('Expected name argument at position %d',[i]);
  472. N:=ansistring(Args[i].VAnsiString);
  473. Inc(I);
  474. With Args[i] do
  475. Case VType of
  476. vtInteger : V:=IntToStr(VInteger);
  477. vtBoolean : V:=BoolToStr(VBoolean,'true','false');
  478. vtChar : V:=VChar;
  479. {$ifndef FPUNONE}
  480. vtExtended : system.Str(VExtended^,V);
  481. {$endif}
  482. vtString : V:=VString^;
  483. vtPChar : V:=VPChar;
  484. vtWideChar : V:=VWideChar;
  485. vtPWideChar : V:=VPWideChar;
  486. vtAnsiString : V:=ansistring(VAnsiString);
  487. vtCurrency : Str(VCurrency^,V);
  488. vtVariant : V:=VVariant^;
  489. vtWideString : V:=Widestring(VWideString);
  490. vtInt64 : V:=IntToStr(vInt64^);
  491. vtQWord : V:=IntToStr(vQWord^);
  492. vtUnicodeString : V:=UnicodeString(VUnicodeString);
  493. end;
  494. Inc(i);
  495. Result:=StringReplace(Result,'{'+N+'}',V,[]);
  496. end;
  497. end;
  498. Function TGoogleAPI.CreateResource(AClass: TGoogleResourceClass
  499. ): TGoogleResource;
  500. begin
  501. Result:=AClass.Create(Self);
  502. Result.SetAPI(Self);
  503. end;
  504. Function TGoogleAPI.CreateResource(const Resource: String): TGoogleResource;
  505. begin
  506. Result:=CreateResource(APIFactory.GetResourceClass(Resource));
  507. end;
  508. finalization
  509. FreeAndNil(TGoogleAPIFactory.DefaultFactory);
  510. end.