2
0

Quick.Config.Json.pas 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278
  1. { ***************************************************************************
  2. Copyright (c) 2015-2021 Kike Pérez
  3. Unit : Quick.Config.Json
  4. Description : Save config to JSON file
  5. Author : Kike Pérez
  6. Version : 1.5
  7. Created : 21/10/2017
  8. Modified : 10/03/2021
  9. This file is part of QuickLib: https://github.com/exilon/QuickLib
  10. ***************************************************************************
  11. Licensed under the Apache License, Version 2.0 (the "License");
  12. you may not use this file except in compliance with the License.
  13. You may obtain a copy of the License at
  14. http://www.apache.org/licenses/LICENSE-2.0
  15. Unless required by applicable law or agreed to in writing, software
  16. distributed under the License is distributed on an "AS IS" BASIS,
  17. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  18. See the License for the specific language governing permissions and
  19. limitations under the License.
  20. *************************************************************************** }
  21. unit Quick.Config.Json;
  22. {$i QuickLib.inc}
  23. interface
  24. uses
  25. Classes,
  26. SysUtils,
  27. {$IFDEF DELPHIXE_UP}
  28. IOUtils,
  29. {$ELSE}
  30. Quick.Files,
  31. {$ENDIF}
  32. Rtti,
  33. Quick.Json.Serializer,
  34. {$IFDEF FPC}
  35. fpjson,
  36. fpjsonrtti,
  37. {$ELSE}
  38. Rest.Json.Types,
  39. System.JSON,
  40. {$ENDIF}
  41. Quick.FileMonitor,
  42. Quick.Config.Base;
  43. type
  44. TFileModifiedEvent = procedure of object;
  45. TLoadConfigEvent = procedure of object;
  46. {$IFNDEF FPC}
  47. TNotSerializableProperty = Quick.Json.Serializer.TNotSerializableProperty;
  48. TCommentProperty = Quick.Json.Serializer.TCommentProperty;
  49. TCustomNameProperty = Quick.Json.Serializer.TCustomNameProperty;
  50. {$ENDIF}
  51. TAppConfigJsonProvider = class(TAppConfigProvider)
  52. private
  53. fFilename : string;
  54. fFileMonitor : TFileMonitor;
  55. fOnFileModified : TFileModifiedEvent;
  56. fLoaded : Boolean;
  57. fReloadIfFileChanged : Boolean;
  58. fOnConfigLoaded : TLoadConfigEvent;
  59. fOnConfigReloaded : TLoadConfigEvent;
  60. fNotifyReload : TLoadConfigEvent;
  61. procedure CreateFileMonitor;
  62. procedure FileModifiedNotify(MonitorNotify : TMonitorNotify);
  63. procedure SetFileName(const Value: string);
  64. procedure SetReloadIfFileChanged(const Value: Boolean);
  65. procedure SetReloadNotify(aNotifyReload : TLoadConfigEvent);
  66. procedure DoNofifyReload;
  67. protected
  68. procedure Load(cConfig : TAppConfig); override;
  69. procedure Save(cConfig : TAppConfig); override;
  70. public
  71. constructor Create(const aFilename : string; aReloadIfFileChanged : Boolean = False); virtual;
  72. destructor Destroy; override;
  73. property Filename : string read fFilename write SetFileName;
  74. property ReloadIfFileChanged : Boolean read fReloadIfFileChanged write SetReloadIfFileChanged;
  75. property IsLoaded : Boolean read fLoaded;
  76. property OnFileModified : TFileModifiedEvent read fOnFileModified write fOnFileModified;
  77. property OnConfigLoaded : TLoadConfigEvent read fOnConfigLoaded write fOnConfigLoaded;
  78. property OnConfigReloaded : TLoadConfigEvent read fOnConfigReloaded write fOnConfigReloaded;
  79. end;
  80. TAppConfigJson = class(TAppConfig)
  81. private
  82. function GetProvider : TAppConfigJsonProvider;
  83. procedure ReloadNotify;
  84. public
  85. constructor Create(const aFilename : string; aReloadIfFileChanged : Boolean = False); virtual;
  86. destructor Destroy; override;
  87. property Provider : TAppConfigJsonProvider read GetProvider;
  88. end;
  89. {Usage: create a descend class from TAppConfigJson and add published properties to be loaded/saved
  90. TMyConfig = class(TAppConfigJson)
  91. private
  92. fName : string;
  93. fSurname : string;
  94. fStatus : Integer;
  95. published
  96. property Name : string read fName write fName;
  97. property SurName : string read fSurname write fSurname;
  98. property Status : Integer read fStatus write fStatus;
  99. end;
  100. MyConfig := TMyConfig.Create;
  101. MyConfig.Provider.FileName := '.\MyAppName.json';
  102. MyConfig.Name := 'John';
  103. MyConfig.Save;
  104. }
  105. implementation
  106. constructor TAppConfigJsonProvider.Create(const aFilename : string; aReloadIfFileChanged : Boolean = False);
  107. begin
  108. inherited Create;
  109. if aFilename = '' then fFilename := TPath.ChangeExtension(ParamStr(0),'json')
  110. else fFilename := aFilename;
  111. fLoaded := False;
  112. fReloadIfFileChanged := aReloadIfFileChanged;
  113. if aReloadIfFileChanged then CreateFileMonitor;
  114. end;
  115. procedure TAppConfigJsonProvider.CreateFileMonitor;
  116. begin
  117. fFileMonitor := TQuickFileMonitor.Create;
  118. fFileMonitor.FileName := fFilename;
  119. fFileMonitor.Interval := 2000;
  120. fFileMonitor.Notifies := [TMonitorNotify.mnFileModified];
  121. fFileMonitor.OnFileChange := FileModifiedNotify;
  122. fFileMonitor.Enabled := True;
  123. end;
  124. destructor TAppConfigJsonProvider.Destroy;
  125. begin
  126. if Assigned(fFileMonitor) then fFileMonitor.Free;
  127. inherited;
  128. end;
  129. procedure TAppConfigJsonProvider.DoNofifyReload;
  130. begin
  131. if Assigned(fNotifyReload) then fNotifyReload
  132. else raise EAppConfig.Create('Not config assigned to reload!');
  133. end;
  134. procedure TAppConfigJsonProvider.FileModifiedNotify(MonitorNotify : TMonitorNotify);
  135. begin
  136. if MonitorNotify = TMonitorNotify.mnFileModified then
  137. begin
  138. if Assigned(fOnFileModified) then fOnFileModified;
  139. if fReloadIfFileChanged then DoNofifyReload;
  140. end;
  141. end;
  142. procedure TAppConfigJsonProvider.Load(cConfig : TAppConfig);
  143. var
  144. json : TStrings;
  145. serializer : TJsonSerializer;
  146. begin
  147. if (not FileExists(fFilename)) and (CreateIfNotExists) then
  148. begin
  149. TAppConfig(cConfig).DefaultValues;
  150. Self.Save(cConfig);
  151. end;
  152. try
  153. json := TStringList.Create;
  154. try
  155. json.LoadFromFile(fFilename);
  156. serializer := TJsonSerializer.Create(slPublishedProperty,UseEnumNames);
  157. try
  158. //Streamer.Options := Streamer.Options + [jsoDateTimeAsString ,jsoUseFormatString];
  159. //Streamer.DateTimeFormat := 'yyyy-mm-dd"T"hh:mm:ss.zz';
  160. serializer.JsonToObject(cConfig,json.Text);
  161. finally
  162. serializer.Free;
  163. end;
  164. finally
  165. json.Free;
  166. end;
  167. if not fLoaded then
  168. begin
  169. fLoaded := True;
  170. if Assigned(fOnConfigLoaded) then fOnConfigLoaded;
  171. end
  172. else if Assigned(fOnConfigReloaded) then fOnConfigReloaded;
  173. except
  174. on e : Exception do raise EAppConfig.Create(e.Message);
  175. end;
  176. end;
  177. procedure TAppConfigJsonProvider.Save(cConfig : TAppConfig);
  178. var
  179. json : TStrings;
  180. Serializer : TJsonSerializer;
  181. begin
  182. if not Assigned(cConfig) then cConfig := TAppConfigJson.Create(fFilename,fReloadIfFileChanged);
  183. try
  184. json := TStringList.Create;
  185. try
  186. serializer := TJsonSerializer.Create(TSerializeLevel.slPublishedProperty,UseEnumNames);
  187. try
  188. //Streamer.Options := Streamer.Options + [jsoDateTimeAsString ,jsoUseFormatString];
  189. //Streamer.DateTimeFormat := 'yyyy-mm-dd"T"hh:mm:ss.zz';
  190. json.Text := serializer.ObjectToJson(cConfig,cConfig.JsonIndent);
  191. finally
  192. serializer.Free;
  193. end;
  194. json.SaveToFile(fFilename);
  195. finally
  196. json.Free;
  197. end;
  198. except
  199. on e : Exception do raise EAppConfig.Create(e.Message);
  200. end;
  201. end;
  202. procedure TAppConfigJsonProvider.SetFileName(const Value: string);
  203. begin
  204. fFilename := Value;
  205. if Assigned(fFileMonitor) then fFileMonitor.Free;
  206. if fReloadIfFileChanged then CreateFileMonitor;
  207. end;
  208. procedure TAppConfigJsonProvider.SetReloadIfFileChanged(const Value: Boolean);
  209. begin
  210. if Value = fReloadIfFileChanged then Exit;
  211. fReloadIfFileChanged := Value;
  212. if Assigned(fFileMonitor) then fFileMonitor.Free;
  213. if fReloadIfFileChanged then CreateFileMonitor;
  214. end;
  215. procedure TAppConfigJsonProvider.SetReloadNotify(aNotifyReload: TLoadConfigEvent);
  216. begin
  217. fNotifyReload := aNotifyReload;
  218. end;
  219. { TAppConfigJson }
  220. constructor TAppConfigJson.Create(const aFilename : string; aReloadIfFileChanged : Boolean = False);
  221. begin
  222. inherited Create(TAppConfigJsonProvider.Create(aFileName,aReloadIfFileChanged));
  223. TAppConfigJsonProvider(fProvider).SetReloadNotify(ReloadNotify);
  224. end;
  225. destructor TAppConfigJson.Destroy;
  226. begin
  227. inherited;
  228. end;
  229. function TAppConfigJson.GetProvider: TAppConfigJsonProvider;
  230. begin
  231. if not Assigned(fProvider) then raise EAppConfig.Create('No provider assigned!');
  232. Result := TAppConfigJsonProvider(fProvider);
  233. end;
  234. procedure TAppConfigJson.ReloadNotify;
  235. begin
  236. Self.Load;
  237. end;
  238. end.