Quick.Config.pas 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270
  1. { ***************************************************************************
  2. Copyright (c) 2015-2018 Kike Pérez
  3. Unit : Quick.Config
  4. Description : Load/Save config from/to JSON file
  5. Author : Kike Pérez
  6. Version : 1.4
  7. Created : 26/01/2017
  8. Modified : 07/04/2018
  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;
  22. interface
  23. {$i QuickLib.inc}
  24. uses
  25. Classes,
  26. SysUtils,
  27. Rtti,
  28. {$IFDEF DELPHIRX102_UP}
  29. DBXJSON,
  30. JSON.Types,
  31. JSON.Serializers;
  32. {$ELSE}
  33. {$IFDEF FPC}
  34. fpjson,
  35. jsonparser,
  36. fpjsonrtti,
  37. Quick.Json.Serializer;
  38. {$ELSE}
  39. Quick.Json.Serializer,
  40. DBXJSON,
  41. System.JSON,
  42. Rest.Json.Types,
  43. Rest.Json;
  44. {$ENDIF}
  45. {$ENDIF}
  46. type
  47. TDateTimeZone = (tzLocal, tzUTC);
  48. IAppConfigProvider<T> = interface
  49. ['{D55B1EBF-47F6-478B-8F70-9444575CB825}']
  50. procedure Load(var cConfig : T);
  51. procedure Save(var cConfig : T);
  52. end;
  53. TSerializeProperty = (spPublic, spPublished);
  54. TAppConfigProviderBase<T : class> = class(TInterfacedObject,IAppConfigProvider<T>)
  55. private
  56. fCreateIfNotExists : Boolean;
  57. fSerializeLevel : TSerializeProperty;
  58. public
  59. constructor Create(var cConfig : T); virtual;
  60. property CreateIfNotExists : Boolean read fCreateIfNotExists write fCreateIfNotExists;
  61. property SerializeLevel : TSerializeProperty read fSerializeLevel write fSerializeLevel;
  62. function InitObject : T;
  63. procedure Load(var cConfig : T); virtual; abstract;
  64. procedure Save(var cConfig : T); virtual; abstract;
  65. end;
  66. TApplyConfigEvent = procedure of object;
  67. {$IFDEF DELPHIXE2_UP}[JsonSerialize(TJsonMemberSerialization.&Public)]{$ENDIF}
  68. TAppConfig = class
  69. private
  70. {$IFDEF FPC}
  71. fOnApplyConfig : TApplyConfigEvent;
  72. fDateTimeZone: TDateTimeZone;
  73. fJsonIndent: Boolean;
  74. fLastSaved : TDateTime;
  75. {$ELSE}
  76. {$IF CompilerVersion < 32.0}[JSONMarshalledAttribute(False)]{$ENDIF}
  77. fOnApplyConfig : TApplyConfigEvent;
  78. {$IF CompilerVersion < 32.0}[JSONMarshalledAttribute(False)]{$ENDIF}
  79. fDateTimeZone: TDateTimeZone;
  80. {$IF CompilerVersion < 32.0}[JSONMarshalledAttribute(False)]{$ENDIF}
  81. fJsonIndent: Boolean;
  82. {$IF CompilerVersion < 32.0}[JSONMarshalledAttribute(False)]{$ENDIF}
  83. fLastSaved : TDateTime;
  84. {$ENDIF}
  85. public
  86. constructor Create; virtual;
  87. {$IFDEF DELPHIRX102_UP}[JsonIgnoreAttribute]{$ENDIF}
  88. property OnApplyConfig : TApplyConfigEvent read fOnApplyConfig write fOnApplyConfig;
  89. {$IFDEF DELPHIRX102_UP}[JsonIgnoreAttribute]{$ENDIF}
  90. property DateTimeZone : TDateTimeZone read fDateTimeZone write fDateTimeZone;
  91. {$IFDEF DELPHIRX102_UP}[JsonIgnoreAttribute]{$ENDIF}
  92. property JsonIndent : Boolean read fJsonIndent write fJsonIndent;
  93. {$IFDEF DELPHIRX102_UP}[JsonIgnoreAttribute]{$ENDIF}
  94. property LastSaved : TDateTime read fLastSaved write fLastSaved;
  95. procedure Apply;
  96. procedure DefaultValues; virtual;
  97. function ToJSON : string;
  98. procedure FromJSON(const json : string);
  99. end;
  100. {Usage: create a descend class from TAppConfig and add published properties to be loaded/saved
  101. TMyConfig = class(TAppConfig)
  102. private
  103. fName : string;
  104. fSurname : string;
  105. fStatus : Integer;
  106. published
  107. property Name : string read fName write fName;
  108. property SurName : string read fSurname write fSurname;
  109. property Status : Integer read fStatus write fStatus;
  110. end;
  111. AppConfigProvider := TAppConfigJsonProvider<TMyConfig>.Create(MyConfig);
  112. MyConfig.Name := 'John';
  113. }
  114. implementation
  115. { TAppConfigProviderBase }
  116. constructor TAppConfigProviderBase<T>.Create(var cConfig : T);
  117. begin
  118. fCreateIfNotExists := True;
  119. fSerializeLevel := spPublished;
  120. //create object with rtti
  121. if Assigned(cConfig) then cConfig.Free;
  122. cConfig := InitObject;
  123. end;
  124. function TAppConfigProviderBase<T>.InitObject : T;
  125. var
  126. AValue: TValue;
  127. ctx: TRttiContext;
  128. rType: TRttiType;
  129. AMethCreate: TRttiMethod;
  130. begin
  131. ctx := TRttiContext.Create;
  132. try
  133. rType := ctx.GetType(TypeInfo(T));
  134. for AMethCreate in rType.GetMethods do
  135. begin
  136. if (AMethCreate.IsConstructor) and (Length(AMethCreate.GetParameters) = 0) then
  137. begin
  138. {$IFDEF FPC}
  139. Result := T(GetClass(T.ClassName).Create);
  140. {$ELSE}
  141. AValue := AMethCreate.Invoke(rType.AsInstance.AsInstance.MetaclassType,[]);
  142. Result := AValue.AsType<T>;
  143. {$ENDIF}
  144. Break;
  145. end;
  146. end;
  147. finally
  148. ctx.Free;
  149. end;
  150. end;
  151. { TAppConfig }
  152. constructor TAppConfig.Create;
  153. begin
  154. fDateTimeZone := TDateTimeZone.tzLocal;
  155. fJsonIndent := True;
  156. fLastSaved := 0;
  157. end;
  158. procedure TAppConfig.Apply;
  159. begin
  160. if Assigned(fOnApplyConfig) then fOnApplyConfig;
  161. end;
  162. procedure TAppConfig.DefaultValues;
  163. begin
  164. //inherit to set default values if no config exists before
  165. end;
  166. function TAppConfig.ToJSON : string;
  167. var
  168. Serializer : TJsonSerializer;
  169. begin
  170. Result := '';
  171. try
  172. {$IFDEF DELPHIRX102_UP}
  173. Serializer := TJsonSerializer.Create;
  174. try
  175. Serializer.Formatting := TJsonFormatting.Indented;
  176. if JsonIndent then Serializer.Formatting := TJsonFormatting.Indented;
  177. if DateTimeZone = TDateTimeZone.tzLocal then
  178. begin
  179. Serializer.DateTimeZoneHandling := TJsonDateTimeZoneHandling.Local;
  180. Serializer.DateFormatHandling := TJsonDateFormatHandling.FormatSettings;
  181. end
  182. else Serializer.DateTimeZoneHandling := TJsonDateTimeZoneHandling.Utc;
  183. Result := Serializer.Serialize<TObject>(Self);
  184. finally
  185. Serializer.Free;
  186. end;
  187. {$ELSE}
  188. serializer := TJsonSerializer.Create(slPublishedProperty);
  189. try
  190. //Streamer.Options := Streamer.Options + [jsoDateTimeAsString ,jsoUseFormatString];
  191. //Streamer.DateTimeFormat := 'yyyy-mm-dd"T"hh:mm:ss.zz';
  192. Result := serializer.ObjectToJSON(Self);
  193. finally
  194. serializer.Free;
  195. end;
  196. {$ENDIF}
  197. except
  198. on e : Exception do raise Exception.Create(e.Message);
  199. end;
  200. end;
  201. procedure TAppConfig.FromJSON(const json : string);
  202. var
  203. Serializer : TJsonSerializer;
  204. begin
  205. try
  206. {$IFDEF DELPHIRX102_UP}
  207. Serializer := TJsonSerializer.Create;
  208. try
  209. Serializer.Formatting := TJsonFormatting.Indented;
  210. if JsonIndent then Serializer.Formatting := TJsonFormatting.Indented;
  211. if DateTimeZone = TDateTimeZone.tzLocal then
  212. begin
  213. Serializer.DateTimeZoneHandling := TJsonDateTimeZoneHandling.Local;
  214. Serializer.DateFormatHandling := TJsonDateFormatHandling.FormatSettings;
  215. end
  216. else Serializer.DateTimeZoneHandling := TJsonDateTimeZoneHandling.Utc;
  217. Self := Serializer.Deserialize<TAppConfig>(json);
  218. finally
  219. Serializer.Free;
  220. end;
  221. {$ELSE}
  222. serializer := TJsonSerializer.Create(slPublishedProperty);
  223. try
  224. //Streamer.Options := Streamer. .Options + [jsoDateTimeAsString ,jsoUseFormatString];
  225. //Streamer.DateTimeFormat := 'yyyy-mm-dd"T"hh:mm:ss.zz';
  226. Self := TAppConfig(serializer.JsonToObject(Self,json));
  227. finally
  228. serializer.Free;
  229. end;
  230. {$ENDIF}
  231. except
  232. on e : Exception do raise Exception.Create(e.Message);
  233. end;
  234. end;
  235. end.