fpjsonrpc.pp 60 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947
  1. {
  2. This file is part of the Free Component Library
  3. JSON-RPC functionality - http independant (backend) part
  4. Copyright (c) 2007 by Michael Van Canneyt [email protected]
  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 fpjsonrpc;
  12. {$mode objfpc}{$H+}
  13. {$inline on}
  14. interface
  15. uses
  16. Classes, SysUtils, fpjson;
  17. Type
  18. { ---------------------------------------------------------------------
  19. JSON-RPC Handler support
  20. ---------------------------------------------------------------------}
  21. TJSONRPCHandlerDef = Class;
  22. TCustomJSONRPCDispatcher = Class;
  23. { TJSONParamDef }
  24. TJSONParamDef = Class(TCollectionItem)
  25. private
  26. FName: TJSONStringType;
  27. FRequired: Boolean;
  28. FType: TJSONtype;
  29. procedure SetName(const AValue: TJSONStringType);
  30. protected
  31. function GetDisplayName: string; override;
  32. public
  33. Constructor Create(ACollection : TCollection); override;
  34. Procedure Assign(Source : TPersistent); override;
  35. Published
  36. Property Name : TJSONStringType Read FName Write SetName;
  37. Property DataType : TJSONtype Read FType Write FType default jtString;
  38. Property Required : Boolean Read FRequired Write FRequired default True;
  39. end;
  40. { TJSONParamDefs }
  41. TJSONParamDefs = Class(TCollection)
  42. private
  43. function GetP(AIndex : Integer): TJSONParamDef;
  44. procedure SetP(AIndex : Integer; const AValue: TJSONParamDef);
  45. Public
  46. Function AddParamDef(Const AName : TJSONStringType; AType : TJSONType = jtString; ARequired: Boolean = False) : TJSONParamDef;
  47. Function IndexOfParamDef(Const AName : TJSONStringType) : Integer;
  48. Function FindParamDef(Const AName : TJSONStringType) : TJSONParamDef;
  49. Function ParamDefByName(Const AName : TJSONStringType) : TJSONParamDef;
  50. Property ParamDefs[AIndex : Integer] : TJSONParamDef Read GetP Write SetP; default;
  51. end;
  52. { TCustomJSONRPCHandler }
  53. TJSONParamErrorEvent = Procedure (Sender : TObject; Const E : Exception; Var Fatal : boolean) of Object;
  54. TJSONRPCOption = (jroCheckParams,jroObjectParams,jroArrayParams,jroIgnoreExtraFields);
  55. TJSONRPCOptions = set of TJSONRPCOption;
  56. { TJSONRPCCallContext }
  57. TJSONRPCCallContext = Class(TObject)
  58. private
  59. FClassName: String;
  60. FMethod: String;
  61. FParamDefinitions: TJSONParamDefs;
  62. FParams: TJSONData;
  63. FTID: String;
  64. procedure SetParams(AValue: TJSONData);
  65. protected
  66. Property ParamDefinitions : TJSONParamDefs Read FParamDefinitions Write FParamDefinitions;
  67. Public
  68. Property Params : TJSONData Read FParams Write SetParams;
  69. // Action used to call handler.
  70. Property ClassName : String Read FClassName Write FClassName;
  71. // Method used to call handler.
  72. Property Method : String Read FMethod Write FMethod;
  73. // Transaction in which handler is called.
  74. Property TID : String Read FTID Write FTID;
  75. end;
  76. TCustomJSONRPCHandler = Class(TComponent)
  77. private
  78. FAfterExecute: TNotifyEvent;
  79. FBeforeExecute: TNotifyEvent;
  80. FOnParamError: TJSONParamErrorEvent;
  81. FOptions: TJSONRPCOptions;
  82. FParamDefs: TJSONParamDefs;
  83. FExecParams : TJSONData;
  84. FResultType: TJSONtype;
  85. FRPCMethodName : String;
  86. function GetRPCMethodName: String;
  87. procedure SetRPCMethodName(AValue: String);
  88. procedure SetParamDefs(const AValue: TJSONParamDefs);
  89. Protected
  90. function CreateParamDefs: TJSONParamDefs; virtual;
  91. Procedure DoCheckParams(Const Params : TJSONData); virtual;
  92. Procedure DoCheckParamDefsOnObject(Const ParamObject: TJSONObject); virtual;
  93. Procedure DoCheckParamArray(const ParamArray: TJSONArray); virtual;
  94. Function DoExecute(Const Params : TJSONData; AContext : TJSONRPCCallContext): TJSONData; virtual;
  95. Property BeforeExecute : TNotifyEvent Read FBeforeExecute Write FBeforeExecute;
  96. Property AfterExecute : TNotifyEvent Read FAfterExecute Write FAfterExecute;
  97. Property OnParamError :TJSONParamErrorEvent Read FOnParamError Write FONParamError;
  98. Property Options : TJSONRPCOptions Read FOptions Write FOptions;
  99. Public
  100. Constructor Create(AOwner : TComponent); override;
  101. Destructor Destroy; override;
  102. Procedure CheckParams(Const Params : TJSONData);
  103. Function ParamByName(Const AName : String) : TJSONData;
  104. // Called before execute is called.
  105. Procedure SetRequestClassAndMethod(const aClassName,aMethodName : String); virtual;
  106. // Actually call method.
  107. Function Execute(Const Params : TJSONData; AContext : TJSONRPCCallContext = Nil) : TJSONData;
  108. // Checked on incoming request
  109. Property ParamDefs : TJSONParamDefs Read FParamDefs Write SetParamDefs;
  110. // Used in parameter descriptions
  111. Property ResultType : TJSONtype Read FResultType Write FResultType;
  112. Property RPCMethodName : String Read GetRPCMethodName Write SetRPCMethodName;
  113. end;
  114. TCustomJSONRPCHandlerClass = Class of TCustomJSONRPCHandler;
  115. TJSONRPCEvent = Procedure (Sender : TObject; Const Params : TJSONData; Out Res : TJSONData) of object;
  116. TJSONContextRPCEvent = Procedure (Sender : TObject; aContext : TJSONRPCCallContext; Const Params : TJSONData; Out Res : TJSONData) of object;
  117. { TJSONRPCHandler }
  118. TJSONRPCHandler = Class(TCustomJSONRPCHandler)
  119. private
  120. FOnExecute: TJSONRPCEvent;
  121. FOnContextExecute : TJSONContextRPCEvent;
  122. protected
  123. Function DoExecute(Const Params : TJSONData; AContext : TJSONRPCCallContext): TJSONData; override;
  124. Published
  125. Property OnExecute : TJSONRPCEvent Read FOnExecute Write FOnExecute;
  126. Property OnContextExecute : TJSONContextRPCEvent Read FOnContextExecute Write FOnContextExecute;
  127. Property BeforeExecute;
  128. Property AfterExecute;
  129. Property OnParamError;
  130. Property Options;
  131. Property ParamDefs;
  132. Property ResultType;
  133. end;
  134. { TJSONRPCEcho }
  135. TJSONRPCEcho = Class(TCustomJSONRPCHandler)
  136. Protected
  137. Function DoExecute(Const Params : TJSONData;AContext : TJSONRPCCallContext): TJSONData; override;
  138. end;
  139. { ---------------------------------------------------------------------
  140. JSON-RPC dispatcher support
  141. ---------------------------------------------------------------------}
  142. TCreateAPIOption = (caoFormatted,caoFullParams);
  143. TCreateAPIOptions = set of TCreateAPIOption;
  144. { TAPIDescriptionCreator }
  145. TAPIDescriptionCreator = Class(TPersistent)
  146. private
  147. FDefaultOptions: TCreateAPIOptions;
  148. FDispatcher: TCustomJSONRPCDispatcher;
  149. FNameSpace : String;
  150. FURL : String;
  151. FAPIType : String;
  152. function GetNameSpace: String;
  153. function isNameSpaceStored: Boolean;
  154. Protected
  155. Function GetOwner: TPersistent; override;
  156. procedure AddParamDefs(O: TJSONObject; Defs: TJSONParamDefs); virtual;
  157. function CreateParamDef(aDef: TJSONParamDef): TJSONObject; virtual;
  158. function HandlerToAPIMethod(H: TCustomJSONRPCHandler; aOptions: TCreateAPIOptions): TJSONObject; virtual;
  159. function HandlerDefToAPIMethod(H: TJSONRPCHandlerDef; aOptions: TCreateAPIOptions): TJSONObject; virtual;
  160. function DefaultNameSpace: String; virtual;
  161. Function PublishHandler(H: TCustomJSONRPCHandler): Boolean; virtual;
  162. function PublishHandlerDef(HD: TJSONRPCHandlerDef): Boolean; virtual;
  163. Public
  164. Constructor Create(aDispatcher : TCustomJSONRPCDispatcher); virtual;
  165. Procedure Assign(Source : TPersistent); override;
  166. function CreateAPI(aOptions: TCreateAPIOptions): TJSONObject; overload;
  167. function CreateAPI : TJSONObject; overload;
  168. Property Dispatcher : TCustomJSONRPCDispatcher Read FDispatcher;
  169. Published
  170. // Namespace for API description. Must be set. Default 'FPWeb'
  171. Property NameSpace : String Read GetNameSpace Write FNameSpace Stored isNameSpaceStored;
  172. // URL property for API router. Must be set.
  173. Property URL : String Read FURL Write FURL;
  174. // "type". By default: 'remoting'
  175. Property APIType : String Read FAPIType Write FAPIType;
  176. // Default options for creating an API
  177. Property DefaultOptions : TCreateAPIOptions Read FDefaultOptions Write FDefaultOptions;
  178. end;
  179. TJSONRPCDispatchOption = (jdoSearchRegistry, // Check JSON Handler registry
  180. jdoSearchOwner, // Check owner (usually webmodule) for request handler
  181. jdoJSONRPC1, // Allow JSON RPC-1
  182. jdoJSONRPC2, // Allow JSON RPC-2
  183. jdoRequireClass, // Require class name (as in Ext.Direct)
  184. jdoNotifications, // Allow JSON Notifications
  185. jdoStrictNotifications, // Error if notification returned result. Default is to discard result.
  186. jdoAllowAPI, // Allow client to get API description
  187. jdoCacheAPI // Cache the API description
  188. );
  189. TJSONRPCDispatchOptions = set of TJSONRPCDispatchOption;
  190. Const
  191. DefaultDispatchOptions = [jdoSearchOwner,jdoJSONRPC1,jdoJSONRPC2,jdoNotifications,jdoAllowAPI,jdoCacheAPI];
  192. Type
  193. TDispatchRequestEvent = Procedure(Sender : TObject; Const AClassName,AMethod : TJSONStringType; Const Params : TJSONData) of object;
  194. TFindRPCHandlerEvent = Procedure(Sender : TObject; Const AClassName,AMethod : TJSONStringType; Out Handler : TCustomJSONRPCHandler) of object;
  195. { TCustomJSONRPCDispatcher }
  196. TCustomJSONRPCDispatcher = Class(TComponent)
  197. private
  198. FAPICreator: TAPIDescriptionCreator;
  199. FFindHandler: TFindRPCHandlerEvent;
  200. FOnDispatchRequest: TDispatchRequestEvent;
  201. FOnEndBatch: TNotifyEvent;
  202. FOnStartBatch: TNotifyEvent;
  203. FOptions: TJSONRPCDispatchOptions;
  204. FCachedAPI : TJSONObject;
  205. FCachedAPIOptions : TCreateAPIOptions;
  206. procedure SetAPICreator(AValue: TAPIDescriptionCreator);
  207. Protected
  208. // Create TAPIDescriptionCreator instance. Must have self as owner
  209. Function CreateAPICreator : TAPIDescriptionCreator; virtual;
  210. // Find handler. If none found, nil is returned. Executes OnFindHandler if needed.
  211. // On return 'DoFree' must be set to indicate that the hand
  212. Function FindHandler(Const AClassName,AMethodName : TJSONStringType;AContext : TJSONRPCCallContext; Out FreeObject : TComponent) : TCustomJSONRPCHandler; virtual;
  213. // Execute handler instance. This can be overridden to implement e.g. authentication globally before actually executing the handler.
  214. Function ExecuteHandler(H: TCustomJSONRPCHandler; Params, ID: TJSONData; AContext: TJSONRPCCallContext): TJSONData; virtual;
  215. // Execute method. Finds handler, and returns response.
  216. Function ExecuteMethod(Const AClassName, AMethodName : TJSONStringType; Params,ID : TJSONData; AContext : TJSONRPCCallContext) : TJSONData; virtual;
  217. // Check and Execute a single request. Exceptions are caught and converted to request error object.
  218. function ExecuteRequest(ARequest: TJSONData;AContext : TJSONRPCCallContext): TJSONData;
  219. // Execute requests, returns responses in same format as requests (single or array)
  220. Function DoExecute(Requests : TJSONData;AContext : TJSONRPCCallContext) : TJSONData; virtual;
  221. // Check if single request corresponds to specs.
  222. // Returns an error object if an error was found.
  223. // if request is OK, then transaction id, classname, method and params *must* be returned.
  224. // The returned transaction id, method, classname and params will be ignored if there is an error.
  225. function CheckRequest(Request: TJSONData; Out AClassName, AMethodName : TJSONStringType; Out ID, Params : TJSONData): TJSONData; virtual;
  226. // Check if requests are OK (check if JSON2 is allowed for array).
  227. Function CheckRequests(Requests : TJSONData) : TJSONData; virtual;
  228. // Format result of a single request. Result is returned to the client, possibly in an array if multiple requests were received in batch.
  229. Function FormatResult(const AClassName, AMethodName: TJSONStringType; const Params, ID, Return: TJSONData) : TJSONData; virtual;
  230. // Format error of a single request. ID will be cloned if non-nil.
  231. function CreateJSON2Error(Const AMessage : String; Const ACode : Integer; ID : TJSONData = Nil; idname : TJSONStringType = 'id' ) : TJSONObject; virtual;
  232. function CreateJSON2Error(Const AFormat : String; Args : Array of const; Const ACode : Integer; ID : TJSONData = Nil; idname : TJSONStringType = 'id') : TJSONObject;
  233. // Hooks for user.
  234. Property OnStartBatch : TNotifyEvent Read FOnStartBatch Write FOnStartBatch;
  235. Property OnDispatchRequest : TDispatchRequestEvent Read FOnDispatchRequest Write FOnDispatchRequest;
  236. Property OnFindHandler : TFindRPCHandlerEvent Read FFindHandler Write FFindHandler;
  237. Property OnEndBatch : TNotifyEvent Read FOnEndBatch Write FOnEndBatch;
  238. Property Options : TJSONRPCDispatchOptions Read FOptions Write FOptions default DefaultDispatchOptions;
  239. Class Function MethodProperty : String; virtual;
  240. Class Function ClassNameProperty : String; virtual;
  241. Class Function ParamsProperty : String; virtual;
  242. Public
  243. Constructor Create(AOwner : TComponent); override;
  244. Destructor Destroy; override;
  245. Class Function TransactionProperty : String; virtual;
  246. // execute request(s) using context
  247. Function Execute(Requests : TJSONData;AContext : TJSONRPCCallContext = Nil) : TJSONData;
  248. // Create an API description. If options are not specified, APICreator.DefaultOptions is used.
  249. Function CreateAPI(aOptions : TCreateAPIOptions): TJSONObject; overload;
  250. Function CreateAPI : TJSONObject; overload;
  251. // Return API Description including namespace, as a string. If options are not specified, APICreator.DefaultOptions is used.
  252. Function APIAsPascal(aOptions : TCreateAPIOptions; aUnitName : string) : String; virtual;
  253. Function APIAsString(aOptions : TCreateAPIOptions) : TJSONStringType; virtual;
  254. Function APIAsString : TJSONStringType; virtual;
  255. Property APICreator : TAPIDescriptionCreator Read FAPICreator Write SetAPICreator;
  256. end;
  257. TJSONRPCDispatcher = Class(TCustomJSONRPCDispatcher)
  258. Published
  259. Property OnStartBatch;
  260. Property OnDispatchRequest;
  261. Property OnFindHandler;
  262. Property OnEndBatch;
  263. Property Options;
  264. Property APICreator;
  265. end;
  266. { ---------------------------------------------------------------------
  267. Factory support
  268. ---------------------------------------------------------------------}
  269. { TJSONRPCHandlerDef }
  270. TDataModuleClass = Class of TDataModule; // For the time being. As of rev 15343 it is in classes unit
  271. TBeforeCreateJSONRPCHandlerEvent = Procedure (Sender : TObject; Var AClass : TCustomJSONRPCHandlerClass) of object;
  272. TJSONRPCHandlerEvent = Procedure (Sender : TObject; AHandler : TCustomJSONRPCHandler) of object;
  273. TJSONRPCHandlerDef = Class(TCollectionItem)
  274. private
  275. FAfterCreate: TJSONRPCHandlerEvent;
  276. FArgumentCount: Integer;
  277. FBeforeCreate: TBeforeCreateJSONRPCHandlerEvent;
  278. FParamDefs: TJSONParamDefs;
  279. FPClass: TCustomJSONRPCHandlerClass;
  280. FDataModuleClass : TDataModuleClass;
  281. FHandlerMethodName: TJSONStringType;
  282. FHandlerClassName: TJSONStringType;
  283. FResultType: TJSONType;
  284. procedure CheckNames(const AClassName, AMethodName: TJSONStringType);
  285. function GetParamDefs: TJSONParamDefs;
  286. procedure SetFPClass(const AValue: TCustomJSONRPCHandlerClass);
  287. procedure SetHandlerClassName(const AValue: TJSONStringType);
  288. procedure SetHandlerMethodName(const AValue: TJSONStringType);
  289. procedure SetParamDefs(AValue: TJSONParamDefs);
  290. protected
  291. Function CreateInstance(AOwner : TComponent; Out AContainer : TComponent) : TCustomJSONRPCHandler; virtual;
  292. Property DataModuleClass : TDataModuleClass Read FDataModuleClass;
  293. Public
  294. Destructor Destroy; override;
  295. Function HaveParamDefs : Boolean;
  296. Property HandlerClassName : TJSONStringType Read FHandlerClassName Write SetHandlerClassName;
  297. Property HandlerMethodName : TJSONStringType Read FHandlerMethodName Write SetHandlerMethodName;
  298. Property HandlerClass : TCustomJSONRPCHandlerClass Read FPClass Write SetFPClass;
  299. Property BeforeCreate : TBeforeCreateJSONRPCHandlerEvent Read FBeforeCreate Write FBeforeCreate;
  300. Property AfterCreate : TJSONRPCHandlerEvent Read FAfterCreate Write FAfterCreate;
  301. Property ArgumentCount : Integer Read FArgumentCount Write FArgumentCount;
  302. Property ParamDefs : TJSONParamDefs Read GetParamDefs Write SetParamDefs;
  303. Property ResultType : TJSONType Read FResultType Write FResultType;
  304. end;
  305. TJSONRPCHandlerDefClass = Class of TJSONRPCHandlerDef;
  306. { TJSONRPCHandlerDefs }
  307. TJSONRPCHandlerDefs = Class(TCollection)
  308. private
  309. function GetH(Index : Integer): TJSONRPCHandlerDef;
  310. procedure SetH(Index : Integer; const AValue: TJSONRPCHandlerDef);
  311. Public
  312. Function IndexOfHandler(Const AClassName,AMethodName : TJSONStringType) : Integer;
  313. Function AddHandler(Const AClassName,AMethodName : TJSONStringType) : TJSONRPCHandlerDef; overload;
  314. Function AddHandler(Const AClassName,AMethodName : TJSONStringType; AClass : TCustomJSONRPCHandlerClass) : TJSONRPCHandlerDef; overload;
  315. Property HandlerDefs[Index : Integer] : TJSONRPCHandlerDef Read GetH Write SetH; default;
  316. end;
  317. { TCustomJSONRPCHandlerManager }
  318. TCustomJSONRPCHandlerManager = Class(TComponent)
  319. Private
  320. FRegistering: Boolean;
  321. {$IFDEF CPU64}
  322. FHandlerCount : Int64;
  323. {$ELSE}
  324. FHandlerCount : Integer;
  325. {$ENDIF}
  326. Protected
  327. procedure Initialize; virtual;
  328. procedure DoClear; virtual;
  329. // Handler support
  330. Procedure RemoveHandlerDef(Const Index : Integer); virtual; abstract;
  331. function AddHandlerDef(Const AClassName,AMethodName : TJSONStringType) : TJSONRPCHandlerDef; virtual; abstract;
  332. function IndexOfHandlerDef(Const AClassName,AMethodName : TJSONStringType) : Integer; virtual; abstract;
  333. function GetHandlerDef(Index : Integer): TJSONRPCHandlerDef; virtual; abstract;
  334. function GetHandlerDefCount: Integer; virtual; abstract;
  335. Public
  336. // Handler support
  337. Procedure UnregisterHandler(Const AClassName, AMethodName : TJSONStringType);
  338. Procedure RegisterDatamodule(Const AClass : TDatamoduleClass; Const AHandlerClassName : TJSONStringType);
  339. Function RegisterHandler(Const AMethodName : TJSONStringType; AClass : TCustomJSONRPCHandlerClass; AArgumentCount : Integer = 0) : TJSONRPCHandlerDef; overload;
  340. Function RegisterHandler(Const AClassName,AMethodName : TJSONStringType; AClass : TCustomJSONRPCHandlerClass; AArgumentCount : Integer = 0) : TJSONRPCHandlerDef; overload;
  341. Function FindHandlerDefByName(Const AClassName,AMethodName : TJSONStringType) : TJSONRPCHandlerDef;
  342. Function GetHandlerDefByName(Const AClassName,AMethodName : TJSONStringType) : TJSONRPCHandlerDef;
  343. Function GetHandler(Const ADef : TJSONRPCHandlerDef; AOwner : TComponent; Out AContainer : TComponent): TCustomJSONRPCHandler;
  344. Function GetHandler(Const AClassName,AMethodName : TJSONStringType; AOwner : TComponent; Out AContainer : TComponent): TCustomJSONRPCHandler;
  345. Procedure GetClassNames (List : TStrings); // Should be a stringlist of TJSONStringType
  346. Procedure GetMethodsOfClass(Const AClassName : TJSONStringType; List : TStrings); // Should be a stringlist of TJSONStringType
  347. Procedure Clear;
  348. // properties
  349. Property Registering : Boolean Read FRegistering;
  350. Property HandlerCount : Integer Read GetHandlerDefCount;
  351. Property HandlerDefs[Index : Integer] : TJSONRPCHandlerDef Read GetHandlerDef;
  352. end;
  353. TCustomJSONRPCHandlerManagerClass = Class of TCustomJSONRPCHandlerManager;
  354. { TJSONRPCHandlerManager }
  355. TJSONRPCHandlerManager = Class(TCustomJSONRPCHandlerManager)
  356. Private
  357. FHandlerDefs : TJSONRPCHandlerDefs;
  358. Protected
  359. procedure DoClear; override;
  360. Function CreateDefs : TJSONRPCHandlerDefs; virtual;
  361. Procedure RemoveHandlerDef(Const Index : Integer); override;
  362. function AddHandlerDef(Const AClassName,AMethodName : TJSONStringType) : TJSONRPCHandlerDef; override;
  363. function IndexOfHandlerDef(Const AClassName,AMethodName : TJSONStringType) : Integer; override;
  364. function GetHandlerDef(Index : Integer): TJSONRPCHandlerDef; override;
  365. function GetHandlerDefCount: Integer; override;
  366. Public
  367. Constructor Create(AOwner : TComponent); override;
  368. Destructor Destroy; override;
  369. end;
  370. { ---------------------------------------------------------------------
  371. Auxiliary stuff
  372. ---------------------------------------------------------------------}
  373. EJSONRPC = Class(Exception);
  374. TJSONErrorObject = Class(TJSONObject);
  375. // Raise EJSONRPC exceptions.
  376. Procedure JSONRPCError(const Msg : String);
  377. Procedure JSONRPCError(const Fmt : String; const Args : Array of const);
  378. Procedure JSONRPCParamError(const Msg: String);
  379. Procedure JSONRPCParamError(const Fmt: String; const Args: array of const);
  380. // Create an 'Error' object for an error response.
  381. function CreateJSONErrorObject(Const AMessage : String; Const ACode : Integer) : TJSONObject;
  382. // Create a JSON RPC 2 error response object containing an 'Error' object.
  383. // Result is of type TJSONErrorObject
  384. // ID is cloned if it is non-nil.
  385. function CreateJSON2ErrorResponse(Const AMessage : String; Const ACode : Integer; ID : TJSONData = Nil; idname : TJSONStringType = 'id' ) : TJSONObject;
  386. function CreateJSON2ErrorResponse(Const AFormat : String; Args : Array of const; Const ACode : Integer; ID : TJSONData = Nil; idname : TJSONStringType = 'id') : TJSONObject;
  387. // Examines Req (request) and returns Error or an array of clones of Error)
  388. Function CreateErrorForRequest(Const Req,Error : TJSONData) : TJSONData;
  389. // Return TCustomJSONRPCHandlerManager instance to use for managing JSON-RPC handler.
  390. Function JSONRPCHandlerManager : TCustomJSONRPCHandlerManager;
  391. Var
  392. // Class that will be created. Must be set before first call to JSONRPCHandlerManager.
  393. JSONRPCHandlerManagerClass : TCustomJSONRPCHandlerManagerClass = TJSONRPCHandlerManager;
  394. // Class of Defs that will be created by TJSONRPCHandlerManager. Must be set before first call to JSONRPCHandlerManager.
  395. DefaultJSONRPCHandlerDefClass : TJSONRPCHandlerDefClass = TJSONRPCHandlerDef;
  396. Const
  397. // JSON RPC 2.0 error codes
  398. EJSONRPCParseError = -32700;
  399. EJSONRPCInvalidRequest = -32600;
  400. EJSONRPCMethodNotFound = -32601;
  401. EJSONRPCInvalidParams = -32602;
  402. EJSONRPCInternalError = -32603;
  403. implementation
  404. uses {$IFDEF WMDEBUG}dbugintf, {$ENDIF} fprpccodegen, fprpcstrings;
  405. function CreateJSONErrorObject(const AMessage: String; const ACode: Integer
  406. ): TJSONObject;
  407. begin
  408. Result:=TJSONErrorObject.Create(['code',ACode,'message',AMessage])
  409. end;
  410. function CreateJSON2ErrorResponse(const AMessage: String; const ACode: Integer;
  411. ID: TJSONData; idname: TJSONStringType): TJSONObject;
  412. begin
  413. If (ID=Nil) then
  414. ID:=TJSONNull.Create
  415. else
  416. ID:=ID.Clone;
  417. Result:=TJSONErrorObject.Create(['jsonrpc','2.0','error',CreateJSONErrorObject(AMessage,ACode),idname,ID]);
  418. end;
  419. function CreateJSON2ErrorResponse(const AFormat: String; Args: array of const;
  420. const ACode: Integer; ID: TJSONData; idname: TJSONStringType): TJSONObject;
  421. begin
  422. If (ID=Nil) then
  423. ID:=TJSONNull.Create
  424. else
  425. ID:=ID.Clone;
  426. Result:=TJSONErrorObject.Create(['jsonrpc','2.0','error',CreateJSONErrorObject(Format(AFormat,Args),ACode),idname,ID]);
  427. end;
  428. function CreateErrorForRequest(const Req, Error: TJSONData): TJSONData;
  429. Var
  430. I : Integer;
  431. begin
  432. if Req is TJSONArray then
  433. begin
  434. Result:=TJSONArray.Create;
  435. TJSONArray(Result).Add(Error);
  436. For I:=1 to TJSONArray(Req).Count-1 do
  437. TJSONArray(Result).Add(Error.Clone);
  438. end
  439. else
  440. Result:=Error;
  441. end;
  442. Var
  443. TheHandler : TCustomJSONRPCHandlerManager;
  444. function JSONRPCHandlerManager: TCustomJSONRPCHandlerManager;
  445. begin
  446. If (TheHandler=Nil) then
  447. TheHandler:=JSONRPCHandlerManagerClass.Create(Nil);
  448. JSONRPCHandlerManager:=TheHandler;
  449. end;
  450. procedure JSONRPCError(const Msg: String);
  451. begin
  452. Raise EJSONRPC.Create(Msg);
  453. end;
  454. procedure JSONRPCError(const Fmt: String; const Args: array of const);
  455. begin
  456. Raise EJSONRPC.CreateFmt(Fmt,Args);
  457. end;
  458. procedure JSONRPCParamError(const Msg: String);
  459. begin
  460. raise EJSONRPC.CreateFmt(SErrParams, [Msg]);
  461. end;
  462. procedure JSONRPCParamError(const Fmt: String; const Args: array of const);
  463. begin
  464. raise EJSONRPC.CreateFmt(SErrParams, [Format(Fmt, Args)]);
  465. end;
  466. { TJSONRPCCallContext }
  467. procedure TJSONRPCCallContext.SetParams(AValue: TJSONData);
  468. begin
  469. if FParams=AValue then Exit;
  470. FParams:=AValue;
  471. end;
  472. { TAPIDescriptionCreator }
  473. function TAPIDescriptionCreator.GetOwner: TPersistent;
  474. begin
  475. Result:=FDispatcher;
  476. end;
  477. constructor TAPIDescriptionCreator.Create(aDispatcher: TCustomJSONRPCDispatcher);
  478. begin
  479. FDispatcher:=aDispatcher;
  480. DefaultOptions:=[caoFullParams];
  481. end;
  482. procedure TAPIDescriptionCreator.Assign(Source: TPersistent);
  483. Var
  484. C : TAPIDescriptionCreator absolute Source;
  485. begin
  486. if Source is TAPIDescriptionCreator then
  487. begin
  488. URL:=C.URL;
  489. NameSpace:=C.FNameSpace;
  490. FAPIType:=C.APIType;
  491. DefaultOptions:=C.DefaultOptions;
  492. end
  493. else
  494. inherited Assign(Source);
  495. end;
  496. { TJSONParamDef }
  497. procedure TJSONParamDef.SetName(const AValue: TJSONStringType);
  498. Var
  499. D: TJSONParamDef;
  500. begin
  501. if FName=AValue then exit;
  502. If Assigned(Collection) and (Collection is TJSONParamDefs) then
  503. begin
  504. D:=(Collection as TJSONParamDefs).FindParamDef(AValue);
  505. If (D<>Nil) and (D<>Self) then
  506. JSONRPCError(SErrDuplicateParam,[AValue]);
  507. end;
  508. FName:=AValue;
  509. end;
  510. function TJSONParamDef.GetDisplayName: string;
  511. begin
  512. Result:=FName;
  513. If (Result='') then
  514. Result:=Inherited GetDisplayName;
  515. end;
  516. constructor TJSONParamDef.Create(ACollection: TCollection);
  517. begin
  518. inherited Create(ACollection);
  519. FType:=jtString;
  520. FRequired:=True;
  521. end;
  522. procedure TJSONParamDef.Assign(Source: TPersistent);
  523. Var
  524. P : TJSONParamDef;
  525. begin
  526. If Source is TJSONParamDef then
  527. begin
  528. P:=TJSONParamDef(Source);
  529. FType:=P.DataType;
  530. FName:=P.Name;
  531. FRequired:=P.Required;
  532. end
  533. else
  534. inherited Assign(Source);
  535. end;
  536. { TJSONParamDefs }
  537. function TJSONParamDefs.GetP(AIndex : Integer): TJSONParamDef;
  538. begin
  539. Result:=TJSONParamDef(Items[AIndex]);
  540. end;
  541. procedure TJSONParamDefs.SetP(AIndex : Integer; const AValue: TJSONParamDef);
  542. begin
  543. Items[AIndex]:=AValue;
  544. end;
  545. function TJSONParamDefs.AddParamDef(const AName: TJSONStringType;
  546. AType: TJSONType; ARequired: Boolean): TJSONParamDef;
  547. begin
  548. Result:=Add as TJSONParamDef;
  549. try
  550. Result.Name:=AName;
  551. Result.DataType:=Atype;
  552. Result.Required:=ARequired;
  553. except
  554. FReeAndNil(Result);
  555. Raise;
  556. end;
  557. end;
  558. function TJSONParamDefs.IndexOfParamDef(const AName: TJSONStringType): Integer;
  559. begin
  560. Result:=Count-1;
  561. While (Result>=0) and (CompareText(AName,GetP(result).Name)<>0) do
  562. Dec(Result);
  563. end;
  564. function TJSONParamDefs.FindParamDef(const AName: TJSONStringType): TJSONParamDef;
  565. Var
  566. I : integer;
  567. begin
  568. I:=IndexOfParamDef(AName);
  569. If (I=-1) then
  570. Result:=Nil
  571. else
  572. Result:=GetP(I);
  573. end;
  574. function TJSONParamDefs.ParamDefByName(const AName: TJSONStringType): TJSONParamDef;
  575. begin
  576. Result:=FindParamDef(AName);
  577. If (Result=Nil) then
  578. JSONRPCError(SErrUnknownParamDef,[AName]);
  579. end;
  580. { TCustomJSONRPCHandler }
  581. procedure TCustomJSONRPCHandler.CheckParams(const Params: TJSONData);
  582. Var
  583. B : Boolean;
  584. begin
  585. Try
  586. DoCheckParams(Params);
  587. Except
  588. On E : Exception do
  589. begin
  590. B:=True;
  591. If Assigned(FonParamError) then
  592. FonParamError(Self,E,B);
  593. If B then
  594. Raise;
  595. end;
  596. end;
  597. end;
  598. function TCustomJSONRPCHandler.ParamByName(const AName: String): TJSONData;
  599. Var
  600. I : Integer;
  601. N : String;
  602. begin
  603. If (FExecParams=Nil) or Not (FExecParams.JSONType in [jtArray,jtObject]) then
  604. Result:=Nil
  605. else
  606. begin
  607. I:=ParamDefs.IndexOfParamDef(AName);
  608. If (I=-1) then
  609. N:=AName
  610. else
  611. N:=ParamDefs[i].Name; // Search with original defined name.
  612. If (FExecParams is TJSONObject) then
  613. Result:=TJSONObject(FExecParams).Elements[N]
  614. else if (FExecParams is TJSONArray) then
  615. begin
  616. If (I=-1) or (I>=FExecParams.Count) then
  617. JSONRPCError(SErrUnknownParamDef,[AName]);
  618. Result:=TJSONArray(FExecParams).Items[i];
  619. end;
  620. end;
  621. end;
  622. procedure TCustomJSONRPCHandler.SetRequestClassAndMethod(const aClassName, aMethodName: String);
  623. begin
  624. // Do nothing
  625. if aClassName=aMethodName then;
  626. end;
  627. procedure TCustomJSONRPCHandler.SetParamDefs(const AValue: TJSONParamDefs);
  628. begin
  629. if FParamDefs=AValue then exit;
  630. FParamDefs.Assign(AValue);
  631. end;
  632. function TCustomJSONRPCHandler.GetRPCMethodName: String;
  633. begin
  634. Result:=FRPCMethodName;
  635. if Result='' then
  636. Result:=Name;
  637. end;
  638. procedure TCustomJSONRPCHandler.SetRPCMethodName(AValue: String);
  639. begin
  640. if aValue=FRPCMethodName then
  641. Exit;
  642. FRPCMethodName:=aValue;
  643. end;
  644. procedure TCustomJSONRPCHandler.DoCheckParams(const Params: TJSONData);
  645. begin
  646. if (Params is TJSONObject) then
  647. begin
  648. if (jroArrayParams in Options) then
  649. JSONRPCParamError(SErrParamsMustBeArray);
  650. DoCheckParamDefsOnObject(Params as TJSONObject);
  651. end else
  652. if (Params is TJSONArray) then
  653. begin
  654. If (jroObjectParams in Options) then
  655. JSONRPCParamError(SErrParamsMustBeArray);
  656. DoCheckParamArray(Params as TJSONArray);
  657. end;
  658. end;
  659. procedure TCustomJSONRPCHandler.DoCheckParamDefsOnObject(
  660. const ParamObject: TJSONObject);
  661. var
  662. def: TJSONParamDef;
  663. Param: TJSONData;
  664. PropEnum: TJSONEnum;
  665. begin
  666. for TCollectionItem(def) in ParamDefs do
  667. begin
  668. // assert the typecast in for loop
  669. Assert(def is TJSONParamDef,'Unexpected ParamDef item class.');
  670. Param:=ParamObject.Find(def.Name);
  671. // check required parameters
  672. if not Assigned(Param) then
  673. begin
  674. if def.Required then
  675. JSONRPCParamError(SErrParamsRequiredParamNotFound,[def.Name])
  676. else
  677. Continue;
  678. end;
  679. // jtUnkown accepts all data types
  680. if (def.DataType<>jtUnknown) and not (Param.JSONType=def.DataType) then
  681. JSONRPCParamError(SErrParamsDataTypeMismatch,[def.Name,JSONTypeName(def.DataType),JSONTypeName(Param.JSONType)]);
  682. end;
  683. // check if additional parameters are given
  684. if not (jroIgnoreExtraFields in Options) then
  685. begin
  686. for PropEnum in ParamObject do
  687. begin
  688. // only check for name is required other specs are checked before
  689. if ParamDefs.FindParamDef(PropEnum.Key)=nil then
  690. JSONRPCParamError(SErrParamsNotAllowd,[PropEnum.Key]);
  691. end;
  692. end;
  693. end;
  694. procedure TCustomJSONRPCHandler.DoCheckParamArray(const ParamArray: TJSONArray);
  695. var
  696. I : Integer;
  697. Param: TJSONData;
  698. Def : TJSONParamDef;
  699. begin
  700. for I:=0 to ParamDefs.Count-1 do
  701. begin
  702. Def:=ParamDefs[i];
  703. if I>=ParamArray.Count then
  704. if ParamDefs[i].Required then
  705. JSONRPCParamError(SErrParamsRequiredParamNotFound,[def.Name]);
  706. Param:=ParamArray[i];
  707. // jtUnkown accepts all data types
  708. if (def.DataType<>jtUnknown) and not (Param.JSONType=def.DataType) then
  709. JSONRPCParamError(SErrParamsDataTypeMismatch,[def.Name,JSONTypeName(def.DataType),JSONTypeName(Param.JSONType)]);
  710. end;
  711. end;
  712. function TCustomJSONRPCHandler.DoExecute(Const Params: TJSONData;AContext : TJSONRPCCallContext): TJSONData;
  713. begin
  714. Result:=Nil;
  715. end;
  716. constructor TCustomJSONRPCHandler.Create(AOwner: TComponent);
  717. begin
  718. inherited Create(AOwner);
  719. FParamDefs:=CreateParamDefs;
  720. end;
  721. destructor TCustomJSONRPCHandler.Destroy;
  722. begin
  723. FreeAndNil(FParamDefs);
  724. inherited Destroy;
  725. end;
  726. function TCustomJSONRPCHandler.CreateParamDefs : TJSONParamDefs;
  727. begin
  728. Result:=TJSONParamDefs.Create(TJSONParamDef);
  729. end;
  730. function TCustomJSONRPCHandler.Execute(Const Params: TJSONData;AContext : TJSONRPCCallContext = Nil): TJSONData;
  731. begin
  732. If Assigned(FBeforeExecute) then
  733. FBeforeExecute(Self);
  734. if (jroCheckParams in Options) then
  735. CheckParams(Params);
  736. FExecParams:=Params;
  737. try
  738. Result:=DoExecute(Params,AContext);
  739. finally
  740. FExecParams:=Nil;
  741. end;
  742. If Assigned(FAfterExecute) then
  743. FAfterExecute(Self);
  744. end;
  745. { TJSONRPCHandler }
  746. function TJSONRPCHandler.DoExecute(const Params: TJSONData;AContext : TJSONRPCCallContext): TJSONData;
  747. begin
  748. Result:=Nil;
  749. If Assigned(FOnContextExecute) then
  750. FOnContextExecute(Self,aContext,Params,Result)
  751. else If Assigned(FOnExecute) then
  752. FOnExecute(Self,Params,Result);
  753. end;
  754. { TJSONRPCEcho }
  755. function TJSONRPCEcho.DoExecute(const Params: TJSONData;AContext : TJSONRPCCallContext): TJSONData;
  756. Var
  757. I : Integer;
  758. A : TJSONArray;
  759. S : TJSONStringType;
  760. begin
  761. If Params is TJSONArray then
  762. begin
  763. A:=Params as TJSONArray;
  764. S:='';
  765. For I:=0 to A.Count-1 do
  766. begin
  767. if (S<>'') then
  768. S:=S+' ';
  769. S:=S+A.Items[i].AsString;
  770. end;
  771. end
  772. else If Params.JSONType in [jtObject,jtNumber] then
  773. S:=Params.AsJSON
  774. else
  775. S:=Params.AsString;
  776. Result:=TJSONString.Create(S);
  777. end;
  778. { TCustomJSONRPCDispatcher }
  779. // Create API method description
  780. Function TAPIDescriptionCreator.CreateParamDef(aDef: TJSONParamDef) : TJSONObject;
  781. begin
  782. With aDef do
  783. Result:=TJSONObject.Create(['name',Name,'type',JSONTypeName(DataType),'required',Required]);
  784. end;
  785. procedure TAPIDescriptionCreator.AddParamDefs(O: TJSONObject; Defs: TJSONParamDefs);
  786. Var
  787. A : TJSONArray;
  788. I : Integer;
  789. begin
  790. A:=TJSONArray.Create;
  791. O.Add('paramdefs',A);
  792. For I:=0 to Defs.Count-1 do
  793. A.Add(CreateParamDef(Defs[i]));
  794. end;
  795. Function TAPIDescriptionCreator.HandlerToAPIMethod (H: TCustomJSONRPCHandler; aOptions : TCreateAPIOptions): TJSONObject;
  796. begin
  797. Result:=TJSONObject.Create(['name',H.Name,'len',H.ParamDefs.Count]);
  798. if Not (caoFullParams in aOptions) then exit;
  799. Result.Add('resulttype',JSONTypeName(H.ResultType));
  800. if (H.ParamDefs.Count>0) then
  801. AddParamDefs(Result,H.ParamDefs);
  802. end;
  803. Function TAPIDescriptionCreator.HandlerDefToAPIMethod (H: TJSONRPCHandlerDef; aOptions: TCreateAPIOptions): TJSONObject;
  804. begin
  805. Result:=TJSONObject.Create(['name',H.HandlerMethodName,'len',H.ArgumentCount]);
  806. if Not (caoFullParams in aOptions) then exit;
  807. Result.Add('resulttype',JSONTypeName(H.ResultType));
  808. if (H.ParamDefs.Count>0) then
  809. AddParamDefs(Result,H.ParamDefs);
  810. end;
  811. function TAPIDescriptionCreator.GetNameSpace: String;
  812. begin
  813. Result:=FNameSpace;
  814. If (Result='') then
  815. Result:=DefaultNameSpace
  816. end;
  817. function TAPIDescriptionCreator.isNameSpaceStored: Boolean;
  818. begin
  819. Result:=NameSpace<>DefaultNameSpace;
  820. end;
  821. function TAPIDescriptionCreator.DefaultNameSpace: String;
  822. begin
  823. Result:='';
  824. end;
  825. function TAPIDescriptionCreator.PublishHandler(H: TCustomJSONRPCHandler): Boolean;
  826. begin
  827. Result:=(H<>Nil)
  828. end;
  829. Function TAPIDescriptionCreator.PublishHandlerDef(HD: TJSONRPCHandlerDef): Boolean;
  830. begin
  831. Result:=(HD<>Nil)
  832. end;
  833. function TAPIDescriptionCreator.CreateAPI(aOptions: TCreateAPIOptions): TJSONObject;
  834. Var
  835. A,D : TJSONObject;
  836. R : TJSONArray;
  837. N : TJSONStringType;
  838. H : TCustomJSONRPCHandler;
  839. I,J : Integer;
  840. M : TCustomJSONRPCHandlerManager;
  841. HD : TJSONRPCHandlerDef;
  842. search : Boolean;
  843. C : TComponent;
  844. begin
  845. D:=TJSONObject.Create;
  846. try
  847. D.Add('url',URL);
  848. D.Add('type',APIType);
  849. A:=TJSONObject.Create;
  850. D.Add('actions',A);
  851. R:=Nil;
  852. N:='';
  853. Search:=assigned(Dispatcher) and (jdoSearchOwner in Dispatcher.Options);
  854. C:=Dispatcher.Owner;
  855. If Search and Assigned(C) then
  856. begin
  857. for I:=C.ComponentCount-1 downto 0 do
  858. If C.Components[i] is TCustomJSONRPCHandler then
  859. begin
  860. H:=C.Components[i] as TCustomJSONRPCHandler;
  861. if PublishHandler(H) then
  862. begin
  863. If (R=Nil) then
  864. begin
  865. N:=C.Name;
  866. R:=TJSONArray.Create;
  867. A.Add(N,R);
  868. end;
  869. R.Add(HandlerToAPIMethod(H,aOptions));
  870. end;
  871. end;
  872. end;
  873. Search:=assigned(Dispatcher) and (jdoSearchRegistry in Dispatcher.Options);
  874. If Search then
  875. begin
  876. M:=JSONRPCHandlerManager;
  877. For I:=M.HandlerCount-1 downto 0 do
  878. begin
  879. HD:=M.HandlerDefs[i];
  880. if PublishHandlerDef(HD) then
  881. begin
  882. If (R=Nil) or (CompareText(N,HD.HandlerClassName)<>0) then
  883. begin
  884. N:=HD.HandlerClassName;
  885. J:=A.IndexOfName(N);
  886. If (J=-1) then
  887. begin
  888. R:=TJSONArray.Create;
  889. A.Add(N,R);
  890. end
  891. else
  892. R:=A.Items[J] as TJSONArray;
  893. end;
  894. R.Add(HandlerDefToAPIMethod(HD,aOptions));
  895. end;
  896. end;
  897. end;
  898. Result:=D;
  899. except
  900. FreeAndNil(D);
  901. Raise;
  902. end;
  903. end;
  904. function TAPIDescriptionCreator.CreateAPI: TJSONObject;
  905. begin
  906. Result:=CreateAPI(DefaultOptions);
  907. end;
  908. procedure TCustomJSONRPCDispatcher.SetAPICreator(AValue: TAPIDescriptionCreator);
  909. begin
  910. if FAPICreator=AValue then Exit;
  911. FAPICreator.Assign(AValue);
  912. end;
  913. function TCustomJSONRPCDispatcher.CreateAPICreator: TAPIDescriptionCreator;
  914. begin
  915. Result:=TAPIDescriptionCreator.Create(Self);
  916. end;
  917. function TCustomJSONRPCDispatcher.FindHandler(const AClassName, AMethodName: TJSONStringType;AContext : TJSONRPCCallContext;Out FreeObject : TComponent): TCustomJSONRPCHandler;
  918. Var
  919. C : TComponent;
  920. D : TJSONRPCHandlerDef;
  921. I : Integer;
  922. begin
  923. Result:=Nil;
  924. FreeObject:=Nil;
  925. If Assigned(Owner) and ((AClassName='') or (CompareText(AClassName,Owner.name)=0)) then
  926. begin
  927. I:=0;
  928. While (Result=Nil) and (I<Owner.ComponentCount) do
  929. begin
  930. C:=Owner.Components[i];
  931. If (C is TCustomJSONRPCHandler) and SameText(TCustomJSONRPCHandler(C).RPCMethodName,aMethodName) then
  932. Result:=TCustomJSONRPCHandler(C);
  933. Inc(I);
  934. end;
  935. end;
  936. If (Result=Nil) and (jdoSearchRegistry in Options) then
  937. begin
  938. D:=JSONRPCHandlerManager.FindHandlerDefByName(AClassName,AMethodName);
  939. If Assigned(D) then
  940. Result:=JSONRPCHandlerManager.GetHandler(D,Self,FreeObject);
  941. end;
  942. If (Result=Nil) and Assigned(FFindHandler) then
  943. begin
  944. FFindhandler(Self,AClassName,AMethodName,Result);
  945. FreeObject:=Nil
  946. end;
  947. end;
  948. Function TCustomJSONRPCDispatcher.ExecuteHandler(H : TCustomJSONRPCHandler; Params,ID: TJSONData;AContext : TJSONRPCCallContext): TJSONData;
  949. begin
  950. Result:=H.Execute(Params,AContext);
  951. end;
  952. function TCustomJSONRPCDispatcher.ExecuteMethod(Const AClassName,AMethodName: TJSONStringType;
  953. Params,ID: TJSONData;AContext : TJSONRPCCallContext): TJSONData;
  954. Var
  955. H : TCustomJSONRPCHandler;
  956. FreeObject : TComponent;
  957. begin
  958. H:=FindHandler(AClassName,AMethodName,AContext,FreeObject);
  959. If (H=Nil) then
  960. begin
  961. // ID is cloned by CreateJSON2Error
  962. if (AClassName='') then
  963. Exit(CreateJSON2Error(SErrInvalidMethodName,[AMethodName],EJSONRPCMethodNotFound,ID,transactionProperty))
  964. else
  965. Exit(CreateJSON2Error(SErrInvalidClassMethodName,[AClassName,AMethodName],EJSONRPCMethodNotFound,ID,transactionProperty));
  966. end;
  967. H.SetRequestClassAndMethod(aClassName,aMethodName);
  968. try
  969. If Assigned(FOndispatchRequest) then
  970. FOndispatchRequest(Self,AClassName,AMethodName,Params);
  971. Result:=ExecuteHandler(H,Params,ID,AContext);
  972. finally
  973. If Assigned(FreeObject) then
  974. FreeAndNil(FreeObject);
  975. end;
  976. end;
  977. function TCustomJSONRPCDispatcher.FormatResult(Const AClassName, AMethodName: TJSONStringType;
  978. Const Params,ID, Return : TJSONData) : TJSONData;
  979. begin
  980. Result:=TJSONObject.Create(['result',Return,transactionproperty,ID.Clone]);
  981. if jdoJSONRPC2 in options then
  982. TJSONObject(Result).Add('jsonrpc','2.0')
  983. else
  984. TJSONObject(Result).Add('error',TJSonNull.Create);
  985. end;
  986. function TCustomJSONRPCDispatcher.CreateJSON2Error(const AMessage: String;
  987. const ACode: Integer; ID: TJSONData; idname: TJSONStringType): TJSONObject;
  988. begin
  989. Result:=CreateJSON2ErrorResponse(AMessage,ACode,ID,IDName);
  990. end;
  991. function TCustomJSONRPCDispatcher.CreateJSON2Error(const AFormat: String;
  992. Args: array of const; const ACode: Integer; ID: TJSONData;
  993. idname: TJSONStringType): TJSONObject;
  994. begin
  995. Result:=CreateJSON2Error(Format(AFormat,Args),ACode,ID,IDName);
  996. end;
  997. function TCustomJSONRPCDispatcher.ExecuteRequest(ARequest: TJSONData;AContext : TJSONRPCCallContext): TJSONData;
  998. Var
  999. C,M : TJSONStringType;
  1000. Id,P : TJSONData;
  1001. begin
  1002. Result:=Nil;
  1003. try
  1004. Result:=CheckRequest(ARequest,C,M,ID,P);
  1005. If (Result=Nil) then
  1006. begin
  1007. If Assigned(AContext) then
  1008. begin
  1009. AContext.ClassName:=C;
  1010. AContext.Method:=M;
  1011. if Assigned(ID) then
  1012. AContext.TID:=ID.AsJSON;
  1013. end;
  1014. Result:=ExecuteMethod(C,M,P,ID,AContext);
  1015. // Do some sanity checks.
  1016. If (Result=Nil) then
  1017. begin
  1018. // No response, and a response was expected.
  1019. if (ID<>Nil) and (jdoStrictNotifications in Options) then
  1020. Result:=CreateJSON2Error(SErrNoResponse,[M],EJSONRPCInternalError,ID,transactionProperty);
  1021. end
  1022. else
  1023. begin
  1024. // A response was received, and no response was expected.
  1025. if ((ID=Nil) or (ID is TJSONNull)) and (jdoStrictNotifications in Options) then
  1026. Result:=CreateJSON2Error(SErrResponseFromNotification,[M],EJSONRPCInternalError,Nil,transactionProperty);
  1027. If (ID=Nil) or (ID is TJSONNull) then // Notification method, discard result.
  1028. FreeAndNil(Result);
  1029. end;
  1030. end;
  1031. If Assigned(Result) and not (Result is TJSONErrorObject) then
  1032. Result:=FormatResult(C,M,P,ID,Result)
  1033. except
  1034. // Something went really wrong if we end up here.
  1035. On E : Exception do
  1036. begin
  1037. If (Result<>Nil) then
  1038. FreeAndNil(Result);
  1039. If Assigned(ID) and not (ID is TJSONNull) then
  1040. Result:=CreateJSON2Error(E.Message,EJSONRPCInternalError,ID,transactionproperty)
  1041. else
  1042. Result:=CreateJSON2Error(E.Message,EJSONRPCInternalError,Nil,transactionproperty);
  1043. end;
  1044. end;
  1045. end;
  1046. function TCustomJSONRPCDispatcher.DoExecute(Requests: TJSONData;AContext : TJSONRPCCallContext): TJSONData;
  1047. Var
  1048. A : TJSONArray;
  1049. Res : TJSONData;
  1050. I : Integer;
  1051. begin
  1052. Result:=Nil;
  1053. If Requests is TJSONArray then
  1054. begin
  1055. A:=Requests as TJSONArray;
  1056. Result:=TJSONArray.Create();
  1057. For I:=0 to A.Count-1 do
  1058. begin
  1059. Res:=ExecuteRequest(A[i],AContext);
  1060. If (Res<>Nil) then
  1061. TJSONArray(Result).Add(Res);
  1062. end;
  1063. end
  1064. else
  1065. Result:=ExecuteRequest(Requests,ACOntext);
  1066. end;
  1067. function TCustomJSONRPCDispatcher.CheckRequest(Request: TJSONData; Out AClassName,AMethodName : TJSONStringType; Out ID, Params : TJSONData): TJSONData;
  1068. Var
  1069. O : TJSONObject;
  1070. I : Integer;
  1071. D : TJSONData;
  1072. OJ2 : Boolean;
  1073. begin
  1074. AMethodName:='';
  1075. AClassName:='';
  1076. ID:=Nil;
  1077. Params:=Nil;
  1078. Result:=Nil;
  1079. If Not (Request is TJSONObject) then
  1080. Exit(CreateJSON2Error(SErrRequestMustBeObject,EJSONRPCInvalidRequest,Nil,transactionproperty));
  1081. O:=TJSONObject(Request);
  1082. // Get ID object, if it exists.
  1083. I:=O.IndexOfName(TransactionProperty);
  1084. If (I<>-1) then
  1085. ID:=O.Items[i];
  1086. // Check ID
  1087. If (ID=Nil) and not (jdoNotifications in Options) then
  1088. Exit(CreateJSON2Error(SErrNoIDProperty,EJSONRPCInvalidRequest,Nil,transactionproperty));
  1089. OJ2:=(jdoJSONRPC2 in Options) and not (jdoJSONRPC1 in Options);
  1090. If OJ2 then
  1091. begin
  1092. if Assigned(ID) and not (ID.JSONType in [jtNull,jtString,jtNumber]) then
  1093. Exit(CreateJSON2Error(SErrINvalidIDProperty,EJSONRPCInvalidRequest,Nil,transactionproperty));
  1094. // Check presence and value of jsonrpc property
  1095. I:=O.IndexOfName('jsonrpc');
  1096. If (I=-1) then
  1097. Exit(CreateJSON2Error(SErrNoJSONRPCProperty,EJSONRPCInvalidRequest,ID,transactionproperty));
  1098. If (O.Items[i].JSONType<>jtString) or (O.Items[i].AsString<>'2.0') then
  1099. Exit(CreateJSON2Error(SErrInvalidJSONRPCProperty,EJSONRPCInvalidRequest,ID,transactionproperty));
  1100. end;
  1101. // Get method name, if it exists.
  1102. I:=O.IndexOfName(MethodProperty);
  1103. If (I<>-1) then
  1104. D:=O.Items[i]
  1105. else
  1106. Exit(CreateJSON2Error(SErrNoMethodName,[MethodProperty],EJSONRPCInvalidRequest,ID,transactionproperty));
  1107. // Check if it is a string
  1108. if Not (D is TJSONString) then
  1109. Exit(CreateJSON2Error(SErrInvalidMethodType,[MethodProperty],EJSONRPCInvalidRequest,ID,transactionproperty));
  1110. AMethodName:=D.AsString;
  1111. If (AMethodName='') then
  1112. Exit(CreateJSON2Error(SErrNoMethodName,[MethodProperty],EJSONRPCInvalidRequest,ID,transactionproperty));
  1113. // Get class name, if it exists and is required
  1114. If (ClassNameProperty<>'') then
  1115. begin
  1116. I:=O.IndexOfName(ClassNameProperty);
  1117. If (I<>-1) then
  1118. D:=O.Items[i]
  1119. else if (jdoRequireClass in options) then
  1120. Exit(CreateJSON2Error(SErrNoClassName,[ClassNameProperty],EJSONRPCInvalidRequest,ID,transactionproperty))
  1121. else
  1122. D:=Nil;
  1123. if Assigned(D) then
  1124. begin
  1125. // Check if it is a string
  1126. if Not (D is TJSONString) then
  1127. Exit(CreateJSON2Error(SErrInvalidClassNameType,[ClassNameProperty],EJSONRPCInvalidRequest,ID,transactionproperty));
  1128. AClassName:=D.AsString;
  1129. If (AClassName='') and (jdoRequireClass in options) then
  1130. Exit(CreateJSON2Error(SErrNoClassName,[ClassNameProperty],EJSONRPCInvalidRequest,ID,transactionproperty));
  1131. end;
  1132. end;
  1133. // Get params, if they exist
  1134. I:=O.IndexOfName(ParamsProperty);
  1135. If (I<>-1) then
  1136. D:=O.Items[i]
  1137. else
  1138. Exit(CreateJSON2Error(SErrNoParams,[ParamsProperty],EJSONRPCInvalidParams,ID,transactionproperty));
  1139. if OJ2 then
  1140. begin
  1141. // Allow array or object
  1142. If Not (D.JSONType in [jtArray,jtObject]) then
  1143. Exit(CreateJSON2Error(SErrParamsMustBeArrayorObject,EJSONRPCInvalidParams,ID,transactionproperty));
  1144. end
  1145. else if not (jdoJSONRPC2 in Options) then
  1146. begin
  1147. // Allow only array
  1148. If Not (D.JSONType in [jtArray]) then
  1149. Exit(CreateJSON2Error(SErrParamsMustBeArray,EJSONRPCInvalidParams,ID,transactionproperty));
  1150. end;
  1151. Params:=D;
  1152. end;
  1153. function TCustomJSONRPCDispatcher.CheckRequests(Requests: TJSONData): TJSONData;
  1154. Var
  1155. A : TJSONArray;
  1156. O : TJSONObject;
  1157. ID : TJSONData;
  1158. I,J : Integer;
  1159. begin
  1160. Result:=Nil;
  1161. If (Requests is TJSONArray) then
  1162. begin
  1163. A:=Requests as TJSONArray;
  1164. If Not (jdoJSONRPC2 in Options) then
  1165. begin
  1166. Result:=TJSONArray.Create;
  1167. For I:=0 to A.Count-1 do
  1168. begin
  1169. ID:=Nil;
  1170. If (A.Items[i] is TJSONObject) then
  1171. begin
  1172. O:=A.Objects[i];
  1173. J:=O.IndexOfName('id');
  1174. if (J<>-1) then
  1175. ID:=O.Items[J];
  1176. end;
  1177. TJSONArray(Result).Add(CreateJSON2ErrorResponse(SErrJSON2NotAllowed,EJSONRPCInvalidRequest,ID,transactionproperty));
  1178. end;
  1179. end;
  1180. end
  1181. else
  1182. If not (Requests is TJSONObject) then
  1183. Result:=CreateJSON2ErrorResponse(SErrRequestMustBeObject,EJSONRPCInvalidRequest,Nil,transactionproperty);
  1184. end;
  1185. class function TCustomJSONRPCDispatcher.TransactionProperty: String;
  1186. begin
  1187. Result:='id'; // Do not localize
  1188. end;
  1189. class function TCustomJSONRPCDispatcher.MethodProperty: String;
  1190. begin
  1191. Result:='method'; // Do not localize
  1192. end;
  1193. class function TCustomJSONRPCDispatcher.ClassNameProperty: String;
  1194. begin
  1195. Result:='classname'; // Do not localize
  1196. end;
  1197. class function TCustomJSONRPCDispatcher.ParamsProperty: String;
  1198. begin
  1199. Result:='params'; // Do not localize
  1200. end;
  1201. constructor TCustomJSONRPCDispatcher.Create(AOwner: TComponent);
  1202. begin
  1203. inherited Create(AOwner);
  1204. FAPICreator:=CreateAPICreator;
  1205. FOptions:=DefaultDispatchOptions;
  1206. end;
  1207. destructor TCustomJSONRPCDispatcher.Destroy;
  1208. begin
  1209. FreeAndNil(FAPICreator);
  1210. FreeAndNil(FCachedAPI);
  1211. inherited Destroy;
  1212. end;
  1213. function TCustomJSONRPCDispatcher.Execute(Requests: TJSONData;AContext : TJSONRPCCallContext = Nil): TJSONData;
  1214. begin
  1215. If Assigned(FOnStartBatch) then
  1216. FOnStartBatch(Self);
  1217. Result:=CheckRequests(Requests);
  1218. if (Result=Nil) then // Form is OK and allowed.
  1219. Result:=DoExecute(Requests,AContext);
  1220. If Assigned(FOnEndBatch) then
  1221. FOnEndBatch(Self);
  1222. end;
  1223. function TCustomJSONRPCDispatcher.CreateAPI(aOptions: TCreateAPIOptions): TJSONObject;
  1224. Var
  1225. CAO : TCreateAPIOptions;
  1226. begin
  1227. CAO:=aOptions-[caoFormatted];
  1228. Result:=Nil;
  1229. if (jdoCacheAPI in Options)
  1230. and (FCachedAPI<>Nil)
  1231. and (CAO=FCachedAPIOptions) then
  1232. Result:=TJSONObject(FCachedAPI.Clone)
  1233. else
  1234. begin
  1235. Result:=APICreator.CreateAPI(aOptions);
  1236. if (jdoCacheAPI in Options) then
  1237. begin
  1238. FCachedAPI:=TJSONObject(Result.Clone);
  1239. FCachedAPIOptions:=CAO;
  1240. end;
  1241. end;
  1242. end;
  1243. function TCustomJSONRPCDispatcher.CreateAPI: TJSONObject;
  1244. begin
  1245. Result:=CreateAPI(APICreator.DefaultOptions);
  1246. end;
  1247. function TCustomJSONRPCDispatcher.APIAsPascal(aOptions: TCreateAPIOptions; aUnitName: string): String;
  1248. Var
  1249. J : TJSONObject;
  1250. Gen : TAPIClientCodeGen;
  1251. begin
  1252. J:=APICreator.CreateAPI(aOptions);
  1253. try
  1254. Gen:=TAPIClientCodeGen.Create(Self);
  1255. if aUnitName='' then
  1256. aUnitName:='services';
  1257. Gen.OutputUnitName:=aUnitName;
  1258. Gen.API:=J;
  1259. Gen.Execute;
  1260. Result:=Gen.Source.Text;
  1261. finally
  1262. Gen.Free;
  1263. J.Free;
  1264. end;
  1265. end;
  1266. function TCustomJSONRPCDispatcher.APIAsString(aOptions: TCreateAPIOptions): TJSONStringType;
  1267. Var
  1268. S : TJSONObject;
  1269. begin
  1270. S:=CreateAPI(aOptions);
  1271. try
  1272. if caoFormatted in aOptions then
  1273. Result:=S.FormatJSON()
  1274. else
  1275. Result:=S.AsJSON;
  1276. if APICreator.NameSpace<>'' then
  1277. Result:=APICreator.NameSpace+' = '+Result;
  1278. finally
  1279. S.Free;
  1280. end;
  1281. end;
  1282. function TCustomJSONRPCDispatcher.APIAsString: TJSONStringType;
  1283. begin
  1284. Result:=APIAsString(APICreator.DefaultOptions);
  1285. end;
  1286. { TJSONRPCHandlerDef }
  1287. procedure TJSONRPCHandlerDef.SetFPClass(const AValue: TCustomJSONRPCHandlerClass
  1288. );
  1289. begin
  1290. FPClass:=AValue;
  1291. end;
  1292. procedure TJSONRPCHandlerDef.CheckNames(const AClassName,
  1293. AMethodName: TJSONStringType);
  1294. Var
  1295. I : Integer;
  1296. begin
  1297. If Assigned(Collection) and (Collection is TJSONRPCHandlerDefs) then
  1298. begin
  1299. I:=TJSONRPCHandlerDefs(Collection).IndexOfHandler(AClassName,AMethodName);
  1300. If (I<>-1) and (Collection.Items[i]<>Self) then
  1301. if (AClassName<>'') then
  1302. JSONRPCError(SErrDuplicateJSONRPCClassHandlerName,[AClassName,AMethodName])
  1303. else
  1304. JSONRPCError(SErrDuplicateJSONRPCHandlerName,[AClassName,AMethodName]);
  1305. end;
  1306. end;
  1307. function TJSONRPCHandlerDef.GetParamDefs: TJSONParamDefs;
  1308. begin
  1309. IF (FParamDefs=Nil) then
  1310. FParamDefs:=TJSONParamDefs.Create(TJSONParamDef);
  1311. Result:=FParamDefs;
  1312. end;
  1313. procedure TJSONRPCHandlerDef.SetHandlerClassName(const AValue: TJSONStringType);
  1314. begin
  1315. if FHandlerClassName=AValue then exit;
  1316. CheckNames(AValue,HandlerMethodName);
  1317. FHandlerClassName:=AValue;
  1318. end;
  1319. procedure TJSONRPCHandlerDef.SetHandlerMethodName(const AValue: TJSONStringType
  1320. );
  1321. begin
  1322. if FHandlerMethodName=AValue then exit;
  1323. CheckNames(HandlerClassName,AValue);
  1324. FHandlerMethodName:=AValue;
  1325. end;
  1326. procedure TJSONRPCHandlerDef.SetParamDefs(AValue: TJSONParamDefs);
  1327. begin
  1328. if FParamDefs=AValue then Exit;
  1329. IF (FParamDefs=Nil) then
  1330. FParamDefs:=TJSONParamDefs.Create(TJSONParamDef);
  1331. if (AValue<>Nil) then
  1332. FParamDefs.Assign(AValue)
  1333. else
  1334. FreeAndNil(FParamDefs);
  1335. end;
  1336. function TJSONRPCHandlerDef.CreateInstance(AOwner: TComponent; out
  1337. AContainer: TComponent): TCustomJSONRPCHandler;
  1338. Var
  1339. AClass : TCustomJSONRPCHandlerClass;
  1340. DM : TDataModule;
  1341. C : TComponent;
  1342. I : Integer;
  1343. begin
  1344. Result:=Nil;
  1345. {$ifdef wmdebug}SendDebug(Format('Creating instance for %s',[Self.HandlerMethodName]));{$endif}
  1346. If Assigned(FDataModuleClass) then
  1347. begin
  1348. {$ifdef wmdebug}SendDebug(Format('Creating datamodule from class %d ',[Ord(Assigned(FDataModuleClass))]));{$endif}
  1349. DM:=FDataModuleClass.Create(Nil);
  1350. {$ifdef wmdebug}SendDebug(Format('Created datamodule from class %s ',[DM.ClassName]));{$endif}
  1351. I:=0;
  1352. While (Result=Nil) and (I<DM.ComponentCount) do
  1353. begin
  1354. C:=DM.Components[i];
  1355. If (C is TCustomJSONRPCHandler) and SameText(TCustomJSONRPCHandler(C).RPCMethodName,FHandlerMethodName) then
  1356. Result:=TCustomJSONRPCHandler(C);
  1357. inc(I);
  1358. end;
  1359. If Result=Nil then
  1360. begin
  1361. FreeAndNil(DM);
  1362. JSONRPCError(SErrUnknownJSONRPCMethodHandler,[FHandlerMethodName]);
  1363. end;
  1364. end
  1365. else
  1366. DM:=TDataModule.CreateNew(Nil,0);
  1367. AContainer:=DM;
  1368. If (Result=Nil) then
  1369. begin
  1370. {$ifdef wmdebug}SendDebug(Format('Creating from class pointer %d ',[Ord(Assigned(FPClass))]));{$endif}
  1371. AClass:=FPCLass;
  1372. If Assigned(FBeforeCreate) then
  1373. FBeforeCreate(Self,AClass);
  1374. Result:=AClass.Create(AContainer);
  1375. end;
  1376. If Assigned(FAfterCreate) then
  1377. FAfterCreate(Self,Result);
  1378. end;
  1379. destructor TJSONRPCHandlerDef.Destroy;
  1380. begin
  1381. FreeAndNil(FParamDefs);
  1382. inherited Destroy;
  1383. end;
  1384. function TJSONRPCHandlerDef.HaveParamDefs: Boolean;
  1385. begin
  1386. Result:=Assigned(FParamDefs);
  1387. end;
  1388. { TJSONRPCHandlerDefs }
  1389. function TJSONRPCHandlerDefs.GetH(Index: Integer): TJSONRPCHandlerDef;
  1390. begin
  1391. Result:=TJSONRPCHandlerDef(Items[Index]);
  1392. end;
  1393. procedure TJSONRPCHandlerDefs.SetH(Index: Integer;
  1394. const AValue: TJSONRPCHandlerDef);
  1395. begin
  1396. Items[Index]:=AValue;
  1397. end;
  1398. function TJSONRPCHandlerDefs.AddHandler(const AClassName,
  1399. AMethodName: TJSONStringType): TJSONRPCHandlerDef;
  1400. begin
  1401. If (IndexOfHandler(AClassName,AMethodName)<>-1) then
  1402. If (AClassName<>'') then
  1403. JSONRPCError(SErrDuplicateJSONRPCClassHandlerName,[AClassName,AMethodName])
  1404. else
  1405. JSONRPCError(SErrDuplicateJSONRPCHandlerName,[AMethodName]);
  1406. Result:=TJSONRPCHandlerDef(Add);
  1407. Result.FHandlerClassName:=AClassName;
  1408. Result.FHandlerMethodName:=AMethodName;
  1409. end;
  1410. function TJSONRPCHandlerDefs.AddHandler(const AClassName,
  1411. AMethodName: TJSONStringType; AClass: TCustomJSONRPCHandlerClass
  1412. ): TJSONRPCHandlerDef;
  1413. begin
  1414. Result:=AddHandler(AClassName,AMethodName);
  1415. Result.HandlerClass:=AClass;
  1416. end;
  1417. function TJSONRPCHandlerDefs.IndexOfHandler(const AClassName,
  1418. AMethodName: TJSONStringType): Integer;
  1419. Function IsMatch(Index : Integer) : Boolean; inline;
  1420. Var
  1421. D : TJSONRPCHandlerDef;
  1422. begin
  1423. D:=GetH(Index);
  1424. Result:=((AClassName='') or
  1425. (CompareText(D.HandlerClassName,AClassName)=0)) and
  1426. (CompareText(AMethodName,D.HandlerMethodName)=0)
  1427. end;
  1428. begin
  1429. Result:=Count-1;
  1430. While (Result>=0) and Not IsMatch(Result) do
  1431. Dec(Result)
  1432. end;
  1433. { TCustomJSONRPCHandlerManager }
  1434. procedure TCustomJSONRPCHandlerManager.Initialize;
  1435. begin
  1436. // Do nothing
  1437. end;
  1438. procedure TCustomJSONRPCHandlerManager.DoClear;
  1439. Var
  1440. I : Integer;
  1441. D : TJSONRPCHandlerDef;
  1442. C,M : String;
  1443. begin
  1444. For I:=HandlerCount-1 downto 0 do
  1445. begin
  1446. D:=HandlerDefs[i];
  1447. C:=D.HandlerClassName;
  1448. M:=D.HandlerMethodName;
  1449. UnregisterHandler(C,M);
  1450. end;
  1451. end;
  1452. Procedure TCustomJSONRPCHandlerManager.UnregisterHandler(Const AClassName,
  1453. AMethodName: TJSONStringType);
  1454. Var
  1455. I : Integer;
  1456. begin
  1457. I:=IndexOfHandlerDef(AClassName,AMethodName);
  1458. If (I<>-1) then
  1459. RemoveHandlerDef(I)
  1460. else
  1461. If (AClassName<>'') then
  1462. JSONRPCError(SErrUnknownJSONRPCClassMethodHandler,[AClassName,AMethodName])
  1463. else
  1464. JSONRPCError(SErrUnknownJSONRPCMethodHandler,[AMethodName]);
  1465. end;
  1466. Procedure TCustomJSONRPCHandlerManager.RegisterDatamodule(
  1467. Const AClass: TDatamoduleClass; Const AHandlerClassName: TJSONStringType);
  1468. Var
  1469. DM : TDatamodule;
  1470. I,J : Integer;
  1471. C : TComponent;
  1472. H : TCustomJSONRPCHandler absolute C;
  1473. D : TJSONRPCHandlerDef;
  1474. B : Boolean;
  1475. CN : TJSONStringType;
  1476. begin
  1477. B:=FRegistering;
  1478. try
  1479. FRegistering:=True;
  1480. DM:=AClass.Create(Self);
  1481. try
  1482. If (AHandlerClassName='') then
  1483. CN:=DM.Name
  1484. else
  1485. CN:=AHandlerClassName;
  1486. For I:=0 to DM.ComponentCount-1 do
  1487. begin
  1488. C:=DM.Components[i];
  1489. if C is TCustomJSONRPCHandler then
  1490. begin
  1491. J:=IndexOfHandlerDef(CN,H.RPCMethodName);
  1492. If (J<>-1) then
  1493. JSONRPCError(SErrDuplicateRPCCLassMethodHandler,[CN,H.RPCMethodName]);
  1494. D:=AddHandlerDef(CN,H.RPCMethodName);
  1495. D.ArgumentCount:=H.ParamDefs.Count;
  1496. D.ParamDefs:=H.ParamDefs;
  1497. D.ResultType:=H.ResultType;
  1498. {$ifdef wmdebug}SendDebug('Registering provider '+C.Name);{$endif}
  1499. D.FDataModuleClass:=TDataModuleClass(DM.ClassType);
  1500. end;
  1501. end;
  1502. finally
  1503. DM.Free;
  1504. end;
  1505. finally
  1506. FRegistering:=B;
  1507. end;
  1508. end;
  1509. Function TCustomJSONRPCHandlerManager.RegisterHandler(
  1510. Const AMethodName: TJSONStringType; AClass: TCustomJSONRPCHandlerClass;
  1511. AArgumentCount: Integer): TJSONRPCHandlerDef;
  1512. begin
  1513. Result:=RegisterHandler('',AMethodName,AClass,AArgumentCount);
  1514. end;
  1515. Function TCustomJSONRPCHandlerManager.RegisterHandler(Const AClassName,
  1516. AMethodName: TJSONStringType; AClass: TCustomJSONRPCHandlerClass;
  1517. AArgumentCount: Integer): TJSONRPCHandlerDef;
  1518. Var
  1519. I : Integer;
  1520. B : Boolean;
  1521. H : TCustomJSONRPCHandler;
  1522. begin
  1523. B:=FRegistering;
  1524. try
  1525. FRegistering:=True;
  1526. I:=IndexOfHandlerDef(AClassName,AMethodname);
  1527. If (I<>-1) then
  1528. If (AClassName<>'') then
  1529. JSONRPCError(SErrDuplicateRPCCLassMethodHandler,[AClassName,AMethodName])
  1530. else
  1531. JSONRPCError(SErrDuplicateRPCMethodHandler,[AMethodName]);
  1532. Result:=AddHandlerDef(AClassName,AMEthodName);
  1533. Result.HandlerClass:=AClass;
  1534. Result.ArgumentCount:=AArgumentCount;
  1535. H:=Aclass.Create(Nil);
  1536. try
  1537. Result.ParamDefs:=H.ParamDefs;
  1538. Result.ResultType:=H.ResultType;
  1539. finally
  1540. H.Free;
  1541. end;
  1542. finally
  1543. FRegistering:=B;
  1544. end;
  1545. end;
  1546. Function TCustomJSONRPCHandlerManager.FindHandlerDefByName(Const AClassName,
  1547. AMethodName: TJSONStringType): TJSONRPCHandlerDef;
  1548. Var
  1549. I : integer;
  1550. begin
  1551. I:=IndexOfHandlerDef(AClassName,AMethodName);
  1552. If (I=-1) then
  1553. Result:=Nil
  1554. else
  1555. Result:=GetHandlerDef(I);
  1556. end;
  1557. Function TCustomJSONRPCHandlerManager.GetHandlerDefByName(Const AClassName,
  1558. AMethodName: TJSONStringType): TJSONRPCHandlerDef;
  1559. begin
  1560. Result:=FindHandlerDefByName(AClassName,AMethodName);
  1561. If (Result=Nil) then
  1562. If (AClassName<>'') then
  1563. JSONRPCError(SErrUnknownJSONRPCClassMethodHandler,[AClassName,AMethodName])
  1564. else
  1565. JSONRPCError(SErrUnknownJSONRPCMethodHandler,[AMethodName]);
  1566. end;
  1567. Function TCustomJSONRPCHandlerManager.GetHandler(
  1568. Const ADef: TJSONRPCHandlerDef; AOwner: TComponent; Out AContainer: TComponent
  1569. ): TCustomJSONRPCHandler;
  1570. Var
  1571. N : String;
  1572. O : TComponent;
  1573. begin
  1574. If AOwner=Nil then
  1575. O:=Self
  1576. else
  1577. O:=AOwner;
  1578. Result:=ADef.CreateInstance(Nil,AContainer);
  1579. N:=aContainer.Name;
  1580. if N='' then
  1581. N:=aContainer.ClassName;
  1582. {$IFDEF CPU64}
  1583. N:=N+IntToStr(InterlockedIncrement64(FHandlerCount));
  1584. {$ELSE}
  1585. N:=N+IntToStr(InterlockedIncrement(FHandlerCount));
  1586. {$ENDIF}
  1587. aContainer.Name:=N;
  1588. O.InsertComponent(aContainer);
  1589. end;
  1590. Function TCustomJSONRPCHandlerManager.GetHandler(Const AClassName,
  1591. AMethodName: TJSONStringType; AOwner: TComponent; Out AContainer: TComponent
  1592. ): TCustomJSONRPCHandler;
  1593. Var
  1594. D : TJSONRPCHandlerDef;
  1595. begin
  1596. D:=GetHandlerDefByname(AClassName,AMEthodName);
  1597. Result:=GetHandler(D,AOwner,AContainer);
  1598. end;
  1599. Procedure TCustomJSONRPCHandlerManager.GetClassNames(List: TStrings);
  1600. Var
  1601. D : TJSONRPCHandlerDef;
  1602. I : Integer;
  1603. begin
  1604. For I:=0 to HandlerCount-1 do
  1605. begin
  1606. D:=HandlerDefs[i];
  1607. If List.IndexOf(D.HandlerClassName)=-1 then
  1608. List.Add(D.HandlerClassName);
  1609. end;
  1610. end;
  1611. Procedure TCustomJSONRPCHandlerManager.GetMethodsOfClass(
  1612. Const AClassName: TJSONStringType; List: TStrings);
  1613. Var
  1614. D : TJSONRPCHandlerDef;
  1615. I : Integer;
  1616. begin
  1617. For I:=0 to HandlerCount-1 do
  1618. begin
  1619. D:=HandlerDefs[i];
  1620. If AClassName=D.HandlerClassName then
  1621. List.Add(D.HandlerMethodName);
  1622. end;
  1623. end;
  1624. Procedure TCustomJSONRPCHandlerManager.Clear;
  1625. begin
  1626. DoClear;
  1627. end;
  1628. { TJSONRPCHandlerManager }
  1629. procedure TJSONRPCHandlerManager.DoClear;
  1630. begin
  1631. FHandlerDefs.Clear;
  1632. end;
  1633. Function TJSONRPCHandlerManager.CreateDefs: TJSONRPCHandlerDefs;
  1634. begin
  1635. Result:=TJSONRPCHandlerDefs.Create(DefaultJSONRPCHandlerDefClass);
  1636. end;
  1637. Procedure TJSONRPCHandlerManager.RemoveHandlerDef(Const Index: Integer);
  1638. begin
  1639. FHandlerDefs.Delete(Index);
  1640. end;
  1641. function TJSONRPCHandlerManager.AddHandlerDef(Const AClassName,
  1642. AMethodName: TJSONStringType): TJSONRPCHandlerDef;
  1643. begin
  1644. Result:=FHandlerDefs.AddHandler(AClassName,AMethodName);
  1645. end;
  1646. function TJSONRPCHandlerManager.IndexOfHandlerDef(Const AClassName,
  1647. AMethodName: TJSONStringType): Integer;
  1648. begin
  1649. Result:=FHandlerDefs.IndexOfHandler(AClassName,AMethodName);
  1650. end;
  1651. function TJSONRPCHandlerManager.GetHandlerDef(Index: Integer
  1652. ): TJSONRPCHandlerDef;
  1653. begin
  1654. Result:=FHandlerDefs[Index];
  1655. end;
  1656. function TJSONRPCHandlerManager.GetHandlerDefCount: Integer;
  1657. begin
  1658. Result:=FHandlerDefs.Count;
  1659. end;
  1660. Constructor TJSONRPCHandlerManager.Create(AOwner: TComponent);
  1661. begin
  1662. inherited Create(AOwner);
  1663. FHandlerDefs:=CreateDefs;
  1664. end;
  1665. Destructor TJSONRPCHandlerManager.Destroy;
  1666. begin
  1667. FreeAndNil(FHandlerDefs);
  1668. inherited Destroy;
  1669. end;
  1670. Initialization
  1671. Finalization
  1672. FreeAndNil(TheHandler);
  1673. end.