brookconstraints.pas 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283
  1. (*
  2. Brook for Free Pascal
  3. Copyright (C) 2014-2019 Silvio Clecio
  4. See the file LICENSE.txt, included in this distribution,
  5. for details about the copyright.
  6. This library is distributed in the hope that it will be useful,
  7. but WITHOUT ANY WARRANTY; without even the implied warranty of
  8. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  9. *)
  10. { Constraints unit. }
  11. unit BrookConstraints;
  12. {$i brook.inc}
  13. interface
  14. uses
  15. BrookClasses, BrookAction, BrookRouter, BrookException, BrookMessages,
  16. Classes, SysUtils;
  17. type
  18. TBrookConstraint = class;
  19. { Handles exceptions for @link(TBrookConstraint). }
  20. EBrookConstraint = class(EBrook)
  21. private
  22. FConstraint: TBrookConstraint;
  23. public
  24. { Creates an instance of a @link(EBrookConstraint) class. }
  25. constructor Create(AConstraint: TBrookConstraint;
  26. const AMsg: string); overload;
  27. { Creates an instance of @code(EBrookConstraint) with a formated message. }
  28. constructor CreateFmt(AConstraint: TBrookConstraint; const AMsg: string;
  29. const AArgs: array of const); overload;
  30. { Frees an instance of @link(EBrookConstraint) class. }
  31. destructor Destroy; override;
  32. { Offers an instance of the current constraint. }
  33. property Constraint: TBrookConstraint read FConstraint;
  34. end;
  35. { Is a metaclass for @link(TBrookCustomConstraint) class. }
  36. TBrookCustomConstraintClass = class of TBrookCustomConstraint;
  37. { Is a metaclass for @link(TBrookConstraint) class. }
  38. TBrookConstraintClass = class of TBrookConstraint;
  39. { Is a metaclass for @link(TBrookCustomConstraints) class. }
  40. TBrookCustomConstraintsClass = class of TBrookCustomConstraints;
  41. { Is a metaclass for @link(TBrookConstraints) class. }
  42. TBrookConstraintsClass = class of TBrookConstraints;
  43. { Offers general features for constraint handling. }
  44. TBrookCustomConstraint = class(TBrookObject)
  45. public
  46. { Raises a message for constraint exceptions. }
  47. procedure Error(const AMsg: string); overload;
  48. { Raises a formated message for constraint exceptions. }
  49. procedure Error(const AMsg: string; const AArgs: array of const); overload;
  50. { Stops the code execution showing an exception message. }
  51. procedure Stop(const AMsg: string); overload;
  52. { Stops the code execution showing a formatted exception message. }
  53. procedure Stop(const AMsg: string; const AArgs: array of const); overload;
  54. { Offers a abstract method for the user validations. }
  55. procedure Execute; virtual; abstract;
  56. end;
  57. { Offers features for constraint handling. }
  58. TBrookConstraint = class(TBrookCustomConstraint)
  59. private
  60. FAction: TBrookAction;
  61. FRoute: TBrookRoute;
  62. public
  63. { Creates an instance of a @link(TBrookConstraint) class. }
  64. constructor Create(AAction: TBrookAction; ARoute: TBrookRoute); virtual;
  65. { Register the constraint class. }
  66. class procedure Register(AActionClass: TBrookActionClass);
  67. { Offers an instance of the current action. }
  68. property Action: TBrookAction read FAction;
  69. { Offers an instance of the current route. }
  70. property Route: TBrookRoute read FRoute;
  71. end;
  72. { Defines a constraint item. }
  73. TBrookConstraintItem = record
  74. ActionClass: TBrookActionClass;
  75. ConstraintClass: TBrookConstraintClass;
  76. end;
  77. PBrookConstraintItem = ^TBrookConstraintItem;
  78. { Registers constraint classes. }
  79. TBrookCustomConstraints = class(TBrookObject)
  80. private
  81. FList: TFPList;
  82. protected
  83. procedure CheckAdd(AActionClass: TBrookActionClass;
  84. AConstraintClass: TBrookCustomConstraintClass);
  85. property List: TFPList read FList;
  86. public
  87. { Creates an instance of a @link(TBrookConstraints) class. }
  88. constructor Create; virtual;
  89. { Frees an instance of @link(TBrookConstraints) class. }
  90. destructor Destroy; override;
  91. end;
  92. { Registers and executes constraint classes. }
  93. TBrookConstraints = class(TBrookCustomConstraints)
  94. public
  95. { Registers the service provided by this class. }
  96. class procedure RegisterService;
  97. { Unregisters the service provided by this class. }
  98. class procedure UnregisterService;
  99. { Return an instance of this class. }
  100. class function Service: TBrookConstraints;
  101. { Adds a constraint item. }
  102. procedure Add(AActionClass: TBrookActionClass;
  103. AConstraintClass: TBrookConstraintClass);
  104. { Triggers the user validations implemented in the constraint. }
  105. procedure Execute(AAction: TBrookAction; ARoute: TBrookRoute); virtual;
  106. end;
  107. implementation
  108. var
  109. _BrookConstraintsService: TBrookConstraints = nil;
  110. _BrookConstraintsServiceClass: TBrookConstraintsClass = nil;
  111. { EBrookConstraint }
  112. constructor EBrookConstraint.Create(AConstraint: TBrookConstraint;
  113. const AMsg: string);
  114. begin
  115. inherited Create(AMsg);
  116. FConstraint := AConstraint;
  117. end;
  118. constructor EBrookConstraint.CreateFmt(AConstraint: TBrookConstraint;
  119. const AMsg: string; const AArgs: array of const);
  120. begin
  121. inherited CreateFmt(AMsg, AArgs);
  122. FConstraint := AConstraint;
  123. end;
  124. destructor EBrookConstraint.Destroy;
  125. begin
  126. FreeAndNil(FConstraint);
  127. inherited Destroy;
  128. end;
  129. { TBrookCustomConstraint }
  130. procedure TBrookCustomConstraint.Error(const AMsg: string);
  131. begin
  132. raise EBrookConstraint.Create(Self, AMsg);
  133. end;
  134. procedure TBrookCustomConstraint.Error(const AMsg: string;
  135. const AArgs: array of const);
  136. begin
  137. raise EBrookConstraint.CreateFmt(Self, AMsg, AArgs);
  138. end;
  139. procedure TBrookCustomConstraint.Stop(const AMsg: string);
  140. begin
  141. raise EBrookAction.Create(AMsg);
  142. end;
  143. procedure TBrookCustomConstraint.Stop(const AMsg: string;
  144. const AArgs: array of const);
  145. begin
  146. raise EBrookAction.CreateFmt(AMsg, AArgs);
  147. end;
  148. { TBrookConstraint }
  149. constructor TBrookConstraint.Create(AAction: TBrookAction; ARoute: TBrookRoute);
  150. begin
  151. inherited Create;
  152. FAction := AAction;
  153. FRoute := ARoute;
  154. end;
  155. class procedure TBrookConstraint.Register(AActionClass: TBrookActionClass);
  156. begin
  157. TBrookConstraints.Service.Add(AActionClass, Self);
  158. end;
  159. { TBrookCustomConstraints }
  160. constructor TBrookCustomConstraints.Create;
  161. begin
  162. inherited Create;
  163. FList := TFPList.Create;
  164. end;
  165. destructor TBrookCustomConstraints.Destroy;
  166. var
  167. PItem: PBrookConstraintItem;
  168. begin
  169. for PItem in FList do
  170. Dispose(PItem);
  171. FList.Free;
  172. inherited Destroy;
  173. end;
  174. procedure TBrookCustomConstraints.CheckAdd(AActionClass: TBrookActionClass;
  175. AConstraintClass: TBrookCustomConstraintClass);
  176. var
  177. PItem: PBrookConstraintItem;
  178. begin
  179. for PItem in FList do
  180. if (PItem^.ActionClass = AActionClass) and
  181. (PItem^.ConstraintClass = AConstraintClass) then
  182. raise EBrookConstraint.CreateFmt(Self,
  183. SBrookConstraintAlreadyRegisteredError, [AConstraintClass.ClassName]);
  184. end;
  185. { TBrookConstraints }
  186. class procedure TBrookConstraints.RegisterService;
  187. begin
  188. if Assigned(_BrookConstraintsServiceClass) then
  189. raise EBrookConstraint.Create(Self,
  190. SBrookConstraintsServiceAlreadyRegisteredError);
  191. _BrookConstraintsServiceClass := Self;
  192. end;
  193. class procedure TBrookConstraints.UnregisterService;
  194. begin
  195. FreeAndNil(_BrookConstraintsService);
  196. _BrookConstraintsServiceClass := nil;
  197. end;
  198. class function TBrookConstraints.Service: TBrookConstraints;
  199. begin
  200. if not Assigned(_BrookConstraintsService) then
  201. begin
  202. if not Assigned(_BrookConstraintsServiceClass) then
  203. raise EBrookConstraint.Create(Self,
  204. SBrookNoConstraintsServiceRegisteredError);
  205. _BrookConstraintsService := _BrookConstraintsServiceClass.Create;
  206. end;
  207. Result := _BrookConstraintsService;
  208. end;
  209. procedure TBrookConstraints.Add(AActionClass: TBrookActionClass;
  210. AConstraintClass: TBrookConstraintClass);
  211. var
  212. PItem: PBrookConstraintItem;
  213. begin
  214. CheckAdd(AActionClass, AConstraintClass);
  215. New(PItem);
  216. PItem^.ActionClass := AActionClass;
  217. PItem^.ConstraintClass := AConstraintClass;
  218. FList.Add(PItem);
  219. end;
  220. procedure TBrookConstraints.Execute(AAction: TBrookAction; ARoute: TBrookRoute);
  221. var
  222. PItem: PBrookConstraintItem;
  223. VConstraint: TBrookConstraint;
  224. begin
  225. for PItem in List do
  226. if PItem^.ActionClass = AAction.ClassType then
  227. begin
  228. VConstraint := PItem^.ConstraintClass.Create(AAction, ARoute);
  229. VConstraint.Execute;
  230. FreeAndNil(VConstraint);
  231. end;
  232. end;
  233. initialization
  234. TBrookConstraints.RegisterService;
  235. finalization
  236. TBrookConstraints.UnregisterService;
  237. end.