extjsjson.pp 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613
  1. {
  2. This file is part of the Free Pascal run time library.
  3. Copyright (c) 2019 by the Free Pascal development team
  4. extjs json
  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. {$IFNDEF FPC_DOTTEDUNITS}
  12. unit extjsjson;
  13. {$ENDIF FPC_DOTTEDUNITS}
  14. {$mode objfpc}{$H+}
  15. interface
  16. {$IFDEF FPC_DOTTEDUNITS}
  17. uses
  18. System.Classes, System.SysUtils, FpWeb.Http.Defs, FpWeb.Http.Base, FpWeb.Data.Base, FpWeb.Data.Extjs.Base, FpJson.Data, Data.Db, FpJson.Parser;
  19. {$ELSE FPC_DOTTEDUNITS}
  20. uses
  21. Classes, SysUtils, httpdefs, fphttp, fpwebdata, fpextjs, fpjson, db, jsonparser;
  22. {$ENDIF FPC_DOTTEDUNITS}
  23. type
  24. { TExtJSJSonWebdataInputAdaptor }
  25. TExtJSJSonWebdataInputAdaptor = CLass(TCustomWebdataInputAdaptor)
  26. private
  27. FRows : TJSONArray;
  28. FCurrentRow : TJSONObject;
  29. FRowIndex : integer;
  30. function CheckData: Boolean;
  31. Public
  32. procedure reset; override;
  33. Function GetNextBatch : Boolean; override;
  34. Function TryFieldValue(Const AFieldName : String; out AValue : String) : Boolean; override;
  35. Destructor destroy; override;
  36. end;
  37. { TExtJSJSONDataFormatter }
  38. TJSONObjectEvent = Procedure(Sender : TObject; AObject : TJSONObject) of Object;
  39. TJSONExceptionObjectEvent = Procedure(Sender : TObject; E : Exception; AResponse : TJSONObject) of Object;
  40. TJSONObjectAllowRowEvent = Procedure(Sender : TObject; Dataset : TDataset; Var Allow : Boolean) of Object;
  41. TJSONObjectAllowEvent = Procedure(Sender : TObject; AObject : TJSONObject; Var Allow : Boolean) of Object;
  42. TExtJSJSONDataFormatter = Class(TExtJSDataFormatter)
  43. private
  44. FAfterDataToJSON: TJSONObjectEvent;
  45. FAfterDelete: TJSONObjectEvent;
  46. FAfterInsert: TJSONObjectEvent;
  47. FAfterRowToJSON: TJSONObjectEvent;
  48. FAfterUpdate: TJSONObjectEvent;
  49. FBeforeDataToJSON: TJSONObjectEvent;
  50. FBeforeDelete: TNotifyEvent;
  51. FBeforeInsert: TNotifyEvent;
  52. FBeforeRowToJSON: TJSONObjectEvent;
  53. FBeforeUpdate: TNotifyEvent;
  54. FOnAllowRow: TJSONObjectAllowRowEvent;
  55. FOnErrorResponse: TJSONExceptionObjectEvent;
  56. FOnMetaDataToJSON: TJSONObjectEvent;
  57. FBatchResult : TJSONArray;
  58. Function AddIdToBatch : TJSONObject;
  59. procedure SendSuccess(ResponseContent: TStream; AddIDValue : Boolean = False);
  60. protected
  61. function AllowRow(ADataset : TDataset) : Boolean; virtual;
  62. Procedure StartBatch(ResponseContent : TStream); override;
  63. Procedure NextBatchItem(ResponseContent : TStream); override;
  64. Procedure EndBatch(ResponseContent : TStream); override;
  65. Function CreateAdaptor(ARequest : TRequest) : TCustomWebdataInputAdaptor; override;
  66. Function AddFieldToJSON(O: TJSONObject; const AFieldName: String; F: TField): TJSONData;
  67. function GetDataContentType: String; override;
  68. Function GetJSONMetaData: TJSONObject;
  69. function RowToJSON: TJSONObject;
  70. Procedure DoBeforeRow(ARow : TJSONObject); virtual;
  71. Procedure DoAfterRow(ARow : TJSONObject); virtual;
  72. Procedure DoBeforeData(AResponse : TJSONObject); virtual;
  73. Procedure DoAfterData(AResponse : TJSONObject); virtual;
  74. Procedure DoOnMetaData(AMetadata : TJSONObject); virtual;
  75. procedure DatasetToStream(Stream: TStream); override;
  76. Procedure DoExceptionToStream(E : Exception; ResponseContent : TStream); override;
  77. Procedure DoInsertRecord(ResponseContent : TStream); override;
  78. Procedure DoUpdateRecord(ResponseContent : TStream); override;
  79. Procedure DoDeleteRecord(ResponseContent : TStream); override;
  80. Public
  81. Destructor destroy; override;
  82. Published
  83. // Called before any fields are added to row object (passed to handler).
  84. Property AfterRowToJSON : TJSONObjectEvent Read FAfterRowToJSON Write FAfterRowToJSON;
  85. // Called After all fields are added to row object (passed to handler).
  86. Property BeforeRowToJSON : TJSONObjectEvent Read FBeforeRowToJSON Write FBeforeRowToJSON;
  87. // Called when metadata object has been created (passed to handler).
  88. Property OnMetaDataToJSON : TJSONObjectEvent Read FOnMetaDataToJSON Write FOnMetaDataToJSON;
  89. // Called when response object has been created, and has Rows property (response passed to handler).
  90. Property AfterDataToJSON : TJSONObjectEvent Read FAfterDataToJSON Write FAfterDataToJSON;
  91. // Called just before response object will be streamed (response passed to handler).
  92. Property BeforeDataToJSON : TJSONObjectEvent Read FBeforeDataToJSON Write FBeforeDataToJSON;
  93. // Called when an exception is caught and formatted.
  94. Property OnErrorResponse : TJSONExceptionObjectEvent Read FOnErrorResponse Write FOnErrorResponse;
  95. // Called to decide whether a record is sent to the client;
  96. Property OnAllowRow : TJSONObjectAllowRowEvent Read FOnAllowRow Write FOnAllowRow;
  97. // After a record was succesfully updated
  98. Property AfterUpdate : TJSONObjectEvent Read FAfterUpdate Write FAfterUpdate;
  99. // After a record was succesfully inserted.
  100. Property AfterInsert : TJSONObjectEvent Read FAfterInsert Write FAfterInsert;
  101. // After a record was succesfully inserted.
  102. Property AfterDelete : TJSONObjectEvent Read FAfterDelete Write FAfterDelete;
  103. // From TCustomHTTPDataContentProducer
  104. Property BeforeUpdate;
  105. Property BeforeInsert;
  106. Property BeforeDelete;
  107. end;
  108. implementation
  109. { $define wmdebug}
  110. {$ifdef wmdebug}
  111. uses dbugintf;
  112. {$endif wmdebug}
  113. Resourcestring
  114. SErrWrongDataFormat = 'Post ROWS data has wrong value type. Expected array or object, got : %s.';
  115. SerrNoExceptionMessage = 'No exception to take error message from.';
  116. Const
  117. // Do not localize these strings
  118. SDefMetaDataProperty = 'metaData';
  119. SDefFieldsProperty = 'fields';
  120. SDefFieldProperty = 'field';
  121. SDefFieldNameProperty = 'name';
  122. SDefDirectionProperty = 'direction';
  123. SDefSortInfoProperty = 'sortInfo';
  124. SIdProperty = 'idProperty';
  125. SSuccessProperty = 'successProperty';
  126. SRootProperty = 'root';
  127. STotalProperty = 'totalProperty';
  128. SDefAscDesc : Array[Boolean] of string = ('ASC','DESC');
  129. function TExtJSJSONDataFormatter.GetDataContentType: String;
  130. begin
  131. Result:='text/html';
  132. end;
  133. function TExtJSJSONDataFormatter.CreateAdaptor(ARequest: TRequest
  134. ): TCustomWebdataInputAdaptor;
  135. begin
  136. Result:=TExtJSJSonWebdataInputAdaptor.Create(Self);
  137. Result.Request:=ARequest;
  138. end;
  139. function TExtJSJSONDataFormatter.AddFieldToJSON(O : TJSONObject; const AFieldName : String; F : TField): TJSONData;
  140. Var
  141. S : String;
  142. begin
  143. if F.IsNull then
  144. Result:=O.Items[O.Add(AFieldName)]
  145. else
  146. Case F.DataType of
  147. ftSmallint,
  148. ftInteger,
  149. ftAutoInc,
  150. ftWord:
  151. Result:=O.Items[O.Add(AFieldName,F.AsInteger)];
  152. ftBoolean:
  153. Result:=O.Items[O.Add(AFieldName,F.AsBoolean)];
  154. ftLargeint:
  155. Result:=O.Items[O.Add(AFieldName,F.AsLargeInt)];
  156. ftDate:
  157. Result:=O.Items[O.Add(AFieldName,FormatDateTime('yyyy-mm-dd',F.AsDateTime))];
  158. ftDateTime:
  159. Result:=O.Items[O.Add(AFieldName,FormatDateTime('yyyy-mm-dd hh":"nn":"ss',F.AsDateTime))];
  160. ftTime:
  161. Result:=O.Items[O.Add(AFieldName,FormatDateTime('hh":"nn":"ss',F.AsDateTime))];
  162. ftMemo,
  163. ftFmtMemo,
  164. ftWideMemo,
  165. ftBlob :
  166. begin
  167. S:=F.AsString;
  168. If (OnTranscode<>Nil) then
  169. OnTranscode(Self,F,S,True);
  170. Result:=O.Items[O.Add(AFieldName,S)];
  171. end;
  172. else
  173. S:=F.DisplayText;
  174. If (OnTranscode<>Nil) then
  175. OnTranscode(Self,F,S,True);
  176. Result:=O.Items[O.Add(AFieldName,S)];
  177. end;
  178. end;
  179. function TExtJSJSONDataFormatter.RowToJSON: TJSONObject;
  180. Var
  181. F : TField;
  182. I : Integer;
  183. begin
  184. Result:=TJSONObject.Create();
  185. try
  186. DobeforeRow(Result);
  187. For I:=0 to Dataset.Fields.Count-1 do
  188. begin
  189. F:=Dataset.Fields[I];
  190. AddFieldToJSON(Result,F.FieldName,F);
  191. end;
  192. DoAfterRow(Result);
  193. except
  194. Result.Free;
  195. Raise;
  196. end;
  197. end;
  198. procedure TExtJSJSONDataFormatter.DoBeforeRow(ARow: TJSONObject);
  199. begin
  200. If Assigned(FBeforeRowToJSON) then
  201. FBeforeRowToJSON(Self,ARow);
  202. end;
  203. procedure TExtJSJSONDataFormatter.DoAfterRow(ARow: TJSONObject);
  204. begin
  205. If Assigned(FAfterRowToJSON) then
  206. FAfterRowToJSON(Self,ARow);
  207. end;
  208. procedure TExtJSJSONDataFormatter.DoBeforeData(AResponse: TJSONObject);
  209. begin
  210. If Assigned(FBeforeDataToJSON) then
  211. FBeforeDataToJSON(Self,AResponse);
  212. end;
  213. procedure TExtJSJSONDataFormatter.DoAfterData(AResponse: TJSONObject);
  214. begin
  215. If Assigned(FAfterDataToJSON) then
  216. FAfterDataToJSON(Self,AResponse);
  217. end;
  218. procedure TExtJSJSONDataFormatter.DoOnMetaData(AMetadata: TJSONObject);
  219. begin
  220. If Assigned(FOnMetaDataToJSON) then
  221. FOnMetaDataToJSON(Self,AMetaData);
  222. end;
  223. Function TExtJSJSONDataFormatter.GetJSONMetaData: TJSONObject;
  224. Var
  225. F : TJSONArray;
  226. Fi : TField;
  227. I : Integer;
  228. O : TJSONObject;
  229. SF,FT : String;
  230. begin
  231. If (SortField='') then
  232. SF:=Dataset.Fields[0].FieldName
  233. else
  234. SF:=SortField;
  235. Result:=TJSonObject.Create;
  236. try
  237. F:=TJSONArray.Create;
  238. Result.add(SDefFieldsProperty,F);
  239. For I:=0 to Dataset.Fields.Count-1 do
  240. begin
  241. Fi:=Dataset.Fields[i];
  242. O:=TJSONObject.Create();
  243. O.Add(SDefFieldNameProperty,Fi.FieldName);
  244. Ft:='';
  245. Case Fi.DataType of
  246. ftInteger,
  247. ftSmallint,
  248. ftWord,
  249. ftLargeInt : FT:='int';
  250. ftCurrency,
  251. ftFloat,
  252. ftBCD : FT:='float';
  253. ftBoolean : ft:='boolean';
  254. ftDate,
  255. ftDateTime,
  256. ftTimeStamp,
  257. ftTime : ft:='date';
  258. ftString,
  259. ftMemo,
  260. ftFmtMemo,
  261. ftFixedChar,
  262. ftWideString,
  263. ftWideMemo : ft:='string'
  264. end;
  265. if (FT<>'') then
  266. begin
  267. O.Add('type',FT);
  268. if (FT='date') then
  269. // Needs improving
  270. Case Fi.DataType of
  271. ftDate : O.Add('dateFormat','Y-m-d');
  272. ftTime : O.Add('dateFormat','H:i:s');
  273. ftDateTime,
  274. ftTimeStamp : O.Add('dateFormat','Y-m-d H:i:s');
  275. end;
  276. end;
  277. F.Add(O);
  278. end;
  279. O:=TJSONObject.Create();
  280. O.Add(SDefFieldProperty,SF);
  281. O.Add(SDefDirectionProperty,SDefAscDesc[SortDescending]);
  282. Result.Add(SDefSortInfoProperty,O);
  283. {$ifdef wmdebug}senddebug('ID property: '+Provider.IDFieldName);{$endif}
  284. Result.Add(SIdProperty,Provider.IDFieldName);
  285. Result.Add(SSuccessProperty, SuccessProperty);
  286. Result.Add(SRootProperty, RowsProperty);
  287. Result.Add(STotalProperty, totalProperty);
  288. DoOnMetaData(Result);
  289. except
  290. Result.free;
  291. Raise;
  292. end;
  293. end;
  294. procedure TExtJSJSONDataFormatter.DatasetToStream(Stream: TStream);
  295. Var
  296. Rows : TJSONArray;
  297. Meta,Resp : TJSONObject;
  298. L : String;
  299. DS : TDataset;
  300. i,RCount,ACount : Integer;
  301. begin
  302. Rows:=Nil;
  303. Resp:=TJSONObject.Create;
  304. try
  305. Rows:=TJSONArray.Create();
  306. Resp.Add(RowsProperty,Rows);
  307. DoBeforeData(Resp);
  308. DS:=Dataset;
  309. DS.First;
  310. RCount:=0;
  311. If MetaData then
  312. begin
  313. Meta:=GetJSONMetaData;
  314. Resp.Add(SDefMetaDataProperty,Meta);
  315. end;
  316. // Go to start
  317. ACount:=PageStart;
  318. While (Not DS.EOF) and (ACount>0) do
  319. begin
  320. DS.Next;
  321. Dec(ACount);
  322. Inc(RCount);
  323. end;
  324. ACount:=PageSize;
  325. While (not DS.EOF) and ((PageSize=0) or (ACount>0)) do
  326. begin
  327. If AllowRow(DS) then
  328. begin
  329. Inc(RCount);
  330. Dec(ACount);
  331. Rows.Add(RowToJSON);
  332. end;
  333. DS.Next;
  334. end;
  335. If (PageSize>0) then
  336. While (not DS.EOF) do
  337. begin
  338. Inc(RCount);
  339. DS.Next;
  340. end;
  341. Resp.Add(SuccessProperty,True);
  342. If (PageSize>0) then
  343. Resp.Add(TotalProperty,RCount);
  344. DoAfterData(Resp);
  345. L:=Resp.AsJSON;
  346. Stream.WriteBuffer(L[1],Length(L));
  347. finally
  348. Resp.Free;
  349. end;
  350. end;
  351. procedure TExtJSJSONDataFormatter.DoExceptionToStream(E: Exception;
  352. ResponseContent: TStream);
  353. Var
  354. Resp : TJSonObject;
  355. L : String;
  356. begin
  357. Resp:=tjsonObject.Create();
  358. try
  359. Resp.Add(SuccessProperty,False);
  360. If Assigned(E) then
  361. Resp.Add(MessageProperty,E.Message)
  362. else
  363. Resp.Add(MessageProperty,SerrNoExceptionMessage);
  364. L:=Resp.AsJSON;
  365. If Length(L)>0 then
  366. ResponseContent.WriteBuffer(L[1],Length(L));
  367. Resp.Add('root',RowsProperty);
  368. Resp.Add(RowsProperty,TJSONArray.Create());
  369. If Assigned(FOnErrorResponse) then
  370. FOnErrorResponse(Self,E,Resp);
  371. finally
  372. Resp.Free;
  373. end;
  374. end;
  375. procedure TExtJSJSONDataFormatter.SendSuccess(ResponseContent: TStream; AddIDValue : Boolean = False);
  376. Var
  377. Resp : TJSonObject;
  378. L : String;
  379. begin
  380. try
  381. Resp:=TJsonObject.Create;
  382. Resp.Add(SuccessProperty,True);
  383. Resp.Add('root',Self.RowsProperty);
  384. If Assigned(FBatchResult) and (FBatchResult.Count>0) then
  385. begin
  386. Resp.Add(Self.RowsProperty,FBatchResult);
  387. FBatchResult:=Nil;
  388. end
  389. else
  390. Resp.Add(Self.RowsProperty,TJSONNull.Create());
  391. L:=Resp.AsJSON;
  392. ResponseContent.WriteBuffer(L[1],Length(L));
  393. finally
  394. Resp.Free;
  395. end;
  396. end;
  397. function TExtJSJSONDataFormatter.AllowRow(ADataset: TDataset): Boolean;
  398. begin
  399. Result:=True;
  400. If Assigned(FOnAllowRow) then
  401. FOnAllowRow(Self,Dataset,Result);
  402. end;
  403. procedure TExtJSJSONDataFormatter.StartBatch(ResponseContent: TStream);
  404. begin
  405. If Assigned(FBatchResult) then
  406. FBatchResult.Clear
  407. else
  408. FBatchResult:=TJSONArray.Create();
  409. end;
  410. procedure TExtJSJSONDataFormatter.NextBatchItem(ResponseContent: TStream);
  411. begin
  412. end;
  413. procedure TExtJSJSONDataFormatter.EndBatch(ResponseContent: TStream);
  414. begin
  415. SendSuccess(Responsecontent,True);
  416. end;
  417. Function TExtJSJSONDataFormatter.AddIdToBatch : TJSONObject;
  418. begin
  419. Result:=TJSONObject.Create([Provider.IDFieldName,Provider.IDFieldValue]);
  420. FBatchResult.Add(Result);
  421. end;
  422. procedure TExtJSJSONDataFormatter.DoInsertRecord(ResponseContent: TStream);
  423. Var
  424. D : TJSONObject;
  425. begin
  426. Inherited;
  427. D:=AddIDToBatch;
  428. If Assigned(FAfterInsert) then
  429. FAfterInsert(Self,D);
  430. end;
  431. procedure TExtJSJSONDataFormatter.DoUpdateRecord(ResponseContent: TStream);
  432. Var
  433. D : TJSONObject;
  434. begin
  435. inherited DoUpdateRecord(ResponseContent);
  436. D:=AddIDToBatch;
  437. If Assigned(FAfterUpdate) then
  438. FAfterUpdate(Self,D);
  439. end;
  440. procedure TExtJSJSONDataFormatter.DoDeleteRecord(ResponseContent: TStream);
  441. begin
  442. inherited DoDeleteRecord(ResponseContent);
  443. If Assigned(FAfterDelete) then
  444. FAfterDelete(Self,Nil);
  445. end;
  446. destructor TExtJSJSONDataFormatter.destroy;
  447. begin
  448. FreeAndNil(FBatchResult);
  449. inherited destroy;
  450. end;
  451. { TExtJSJSonWebdataInputAdaptor }
  452. function TExtJSJSonWebdataInputAdaptor.CheckData : Boolean;
  453. Var
  454. D : TJSONData;
  455. P : TJSONParser;
  456. S : String;
  457. begin
  458. Result:=Assigned(FCurrentRow);
  459. If Not (Result) and TryParamValue('rows',S) then
  460. begin
  461. {$ifdef wmdebug}senddebug('Check data: '+GetParamValue('rows'));{$endif}
  462. P:=TJSONParser.Create(S);
  463. try
  464. D:=P.Parse;
  465. {$ifdef wmdebug}senddebug('Classname : '+D.ClassName);{$endif}
  466. If D is TJSONArray then
  467. begin
  468. FRows:=TJSONArray(D);
  469. FRowIndex:=0;
  470. FCurrentRow:=FRows.Items[0] as TJSONObject;
  471. end
  472. else If D is TJSONObject then
  473. begin
  474. FRows:=Nil;
  475. FCurrentRow:=TJSONObject(D);
  476. end
  477. else if D is TJSONInt64Number then
  478. begin
  479. FRows:=nil;
  480. FCurrentRow:=TJSONObject.Create(['ID',D]);
  481. end
  482. else
  483. begin
  484. FreeAndNil(D);
  485. Raise EFPHTTPError.CreateFmt(SErrWrongDataFormat,[D.ClassName]);
  486. end;
  487. Result:=True;
  488. finally
  489. P.Free;
  490. end;
  491. end;
  492. end;
  493. procedure TExtJSJSonWebdataInputAdaptor.reset;
  494. begin
  495. If (FRows=Nil) then
  496. FreeAndNil(FCurrentRow)
  497. else
  498. FreeAndNil(FRows);
  499. FRowIndex:=0;
  500. inherited reset;
  501. end;
  502. function TExtJSJSonWebdataInputAdaptor.GetNextBatch: Boolean;
  503. begin
  504. If (FRows=Nil) then
  505. Result:=inherited GetNextBatch
  506. else
  507. begin
  508. Result:=FRowindex<FRows.Count-1;
  509. Inc(FRowIndex);
  510. If Result then
  511. FCurrentRow:=FRows.Items[FRowIndex] as TJSONObject
  512. else
  513. FCurrentRow:=Nil;
  514. end;
  515. end;
  516. function TExtJSJSonWebdataInputAdaptor.TryFieldValue(const AFieldName: String;
  517. out AValue: String): Boolean;
  518. Var
  519. I : Integer;
  520. begin
  521. Result:=False;
  522. if CheckData then
  523. begin
  524. I:=FCurrentRow.IndexOfName(AFieldName);
  525. Result:=I<>-1;
  526. if result and (FCurrentRow.Items[I].JSONType<>jtNull) then
  527. AValue:=FCurrentRow.Items[I].AsString;
  528. end;
  529. end;
  530. destructor TExtJSJSonWebdataInputAdaptor.destroy;
  531. begin
  532. If Assigned(FRows) then
  533. FreeAndNil(FRows)
  534. else if assigned(FCurrentRow) then
  535. FreeAndNil(FCurrentRow);
  536. inherited destroy;
  537. end;
  538. initialization
  539. WebDataProviderManager.RegisterInputAdaptor('ExtJS - JSON',TExtJSJSONWebdataInputAdaptor);
  540. WebDataProviderManager.RegisterDataProducer('ExtJS - JSON',TExtJSJSONDataFormatter);
  541. finalization
  542. WebDataProviderManager.UnRegisterInputAdaptor('ExtJS - JSON');
  543. WebDataProviderManager.UnRegisterDataProducer('ExtJS - JSON')
  544. end.