
git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@4385 8e941d3f-bd1b-0410-a28a-d453659cc2b4
307 lines
6.9 KiB
ObjectPascal
307 lines
6.9 KiB
ObjectPascal
{
|
|
This file is part of the Web Service Toolkit
|
|
Copyright (c) 2007 by Inoussa OUEDRAOGO
|
|
|
|
This file is provide under modified LGPL licence
|
|
( the files COPYING.modifiedLGPL and COPYING.LGPL).
|
|
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
}
|
|
{$INCLUDE wst_global.inc}
|
|
unit json_formatter;
|
|
|
|
interface
|
|
|
|
uses
|
|
Classes, SysUtils, TypInfo,
|
|
base_service_intf, service_intf, imp_utils,
|
|
base_json_formatter, fpjson, SyncObjs;
|
|
|
|
type
|
|
|
|
{$M+}
|
|
|
|
{ TJsonRpcFormatter }
|
|
|
|
TJsonRpcFormatter = class(TJsonRpcBaseFormatter,IFormatterClient)
|
|
private
|
|
FCallProcedureName : string;
|
|
FCallTarget : string;
|
|
FVersion : string;
|
|
FVersionEnum : TJonRPCVersion;
|
|
private
|
|
procedure SetVersion(const AValue : string);
|
|
public
|
|
constructor Create();override;
|
|
|
|
procedure BeginCall(
|
|
const AProcName,
|
|
ATarget : string;
|
|
ACallContext : ICallContext
|
|
);
|
|
procedure EndCall();
|
|
procedure BeginCallRead(ACallContext : ICallContext);
|
|
|
|
function GetCallProcedureName():string;
|
|
function GetCallTarget():string;
|
|
property VersionEnum : TJonRPCVersion read FVersionEnum;
|
|
published
|
|
property Version : string read FVersion write SetVersion;
|
|
end;
|
|
|
|
{ TJsonRpcCallMaker }
|
|
|
|
TJsonRpcCallMaker = class(TSimpleFactoryItem,ICallMaker)
|
|
Private
|
|
FPropMngr : IPropertyManager;
|
|
Public
|
|
constructor Create();override;
|
|
destructor Destroy();override;
|
|
function GetPropertyManager():IPropertyManager;
|
|
procedure MakeCall(
|
|
ASerializer : IFormatterClient;
|
|
ATransport : ITransport
|
|
);
|
|
End;
|
|
|
|
TJsonRpcCustomIdManager = class
|
|
public
|
|
function GetNewID() : PtrInt;virtual;abstract;
|
|
end;
|
|
|
|
{ TJsonRpcSequencedIdManager }
|
|
|
|
TJsonRpcSequencedIdManager = class(TJsonRpcCustomIdManager)
|
|
private
|
|
FIdSequence : PtrInt;
|
|
FIdSequenceLock : TCriticalSection;
|
|
public
|
|
constructor Create();
|
|
destructor Destroy();override;
|
|
function GetNewID() : PtrInt;override;
|
|
end;
|
|
|
|
procedure RegisterJsonProtocol();
|
|
procedure SetIdManager(AValue : TJsonRpcCustomIdManager);{$IFDEF USE_INLINE}inline;{$ENDIF}
|
|
function GetIdManager():TJsonRpcCustomIdManager ;{$IFDEF USE_INLINE}inline;{$ENDIF}
|
|
|
|
implementation
|
|
uses
|
|
StrUtils;
|
|
|
|
var
|
|
FIdManager : TJsonRpcCustomIdManager;
|
|
|
|
function GetIdManager():TJsonRpcCustomIdManager ;
|
|
begin
|
|
Result := FIdManager;
|
|
end;
|
|
|
|
procedure SetIdManager(AValue : TJsonRpcCustomIdManager);
|
|
begin
|
|
FreeAndNil(FIdManager);
|
|
FIdManager := AValue;
|
|
end;
|
|
|
|
{ TJsonRpcFormatter }
|
|
|
|
procedure TJsonRpcFormatter.SetVersion(const AValue : string);
|
|
var
|
|
i : Integer;
|
|
begin
|
|
if ( FVersion = AValue ) then
|
|
Exit;
|
|
i := AnsiIndexStr(AValue,[s_json_rpc_version_10,s_json_rpc_version_11]);
|
|
if ( i < 0 ) then
|
|
Error('JSON-RPC version not supported : %s',[AValue]);
|
|
FVersion := AValue;
|
|
FVersionEnum := TJonRPCVersion(i);
|
|
end;
|
|
|
|
constructor TJsonRpcFormatter.Create();
|
|
begin
|
|
inherited Create();
|
|
SetVersion(s_json_rpc_version_10);
|
|
end;
|
|
|
|
procedure TJsonRpcFormatter.BeginCall(
|
|
const AProcName, ATarget : string;
|
|
ACallContext : ICallContext
|
|
);
|
|
begin
|
|
FCallProcedureName := AProcName;
|
|
FCallTarget := ATarget;
|
|
|
|
case VersionEnum of
|
|
jsonRPC_10 :
|
|
begin
|
|
BeginObject('',Nil);
|
|
Put(s_json_method,TypeInfo(string),FCallProcedureName);
|
|
BeginArray(s_json_params,Nil,nil,[0,0],asScoped);
|
|
end;
|
|
jsonRPC_11 :
|
|
begin
|
|
BeginObject('',Nil);
|
|
Put(s_json_version,TypeInfo(string),Version);
|
|
Put(s_json_method,TypeInfo(string),FCallProcedureName);
|
|
BeginArray(s_json_params,Nil,nil,[0,0],asScoped);
|
|
end;
|
|
else
|
|
Error('JSON-RPC version not supported : %s',[Version]);
|
|
end;
|
|
end;
|
|
|
|
procedure TJsonRpcFormatter.EndCall();
|
|
var
|
|
i : PtrInt;
|
|
begin
|
|
EndScope(); // params
|
|
if ( VersionEnum = jsonRPC_10 ) then begin
|
|
if Assigned(FIdManager) then
|
|
i := FIdManager.GetNewID()
|
|
else
|
|
i := 0;
|
|
Put(s_json_id,TypeInfo(PtrInt),i);
|
|
end;
|
|
EndScope(); // Root object
|
|
end;
|
|
|
|
procedure TJsonRpcFormatter.BeginCallRead(ACallContext : ICallContext);
|
|
Var
|
|
errCode, errMsg : string;
|
|
e : EJsonRpcException;
|
|
elt : TJSONData;
|
|
remoteErr : TJSONObject;
|
|
i : Integer;
|
|
begin
|
|
ClearStack();
|
|
PushStack(GetRootData(),stObject);
|
|
elt := GetRootData().Find(s_json_error);
|
|
if Assigned(elt) and elt.InheritsFrom(TJSONObject) then begin
|
|
remoteErr := TJSONObject(elt);
|
|
i := remoteErr.IndexOfName(s_json_code);
|
|
if ( i > -1 ) then
|
|
errCode := remoteErr.Items[i].AsString
|
|
else
|
|
errCode := '';
|
|
i := remoteErr.IndexOfName(s_json_message);
|
|
if ( i > -1 ) then
|
|
errMsg := remoteErr.Items[i].AsString
|
|
else
|
|
errMsg := remoteErr.AsJSON;
|
|
e := EJsonRpcException.Create(errMsg);
|
|
e.FaultCode := errCode;
|
|
e.FaultString := errMsg;
|
|
raise e;
|
|
end;
|
|
end;
|
|
|
|
function TJsonRpcFormatter.GetCallProcedureName() : string;
|
|
begin
|
|
Result := FCallProcedureName;
|
|
end;
|
|
|
|
function TJsonRpcFormatter.GetCallTarget() : string;
|
|
begin
|
|
Result := FCallTarget;
|
|
end;
|
|
|
|
{ TJsonRpcCallMaker }
|
|
|
|
constructor TJsonRpcCallMaker.Create();
|
|
begin
|
|
FPropMngr := TPublishedPropertyManager.Create(Self);
|
|
end;
|
|
|
|
destructor TJsonRpcCallMaker.Destroy();
|
|
begin
|
|
FPropMngr := Nil;
|
|
inherited Destroy();
|
|
end;
|
|
|
|
function TJsonRpcCallMaker.GetPropertyManager() : IPropertyManager;
|
|
begin
|
|
Result:= FPropMngr;
|
|
end;
|
|
|
|
procedure TJsonRpcCallMaker.MakeCall(
|
|
ASerializer : IFormatterClient;
|
|
ATransport : ITransport
|
|
);
|
|
var
|
|
rqt, rsps : TMemoryStream;
|
|
propMngr : IPropertyManager;
|
|
begin
|
|
Assert(Assigned(ASerializer));
|
|
Assert(Assigned(ATransport));
|
|
propMngr := ATransport.GetPropertyManager();
|
|
propMngr.SetProperty(
|
|
sCONTENT_TYPE,
|
|
s_json
|
|
);
|
|
propMngr.SetProperty(
|
|
sFORMAT,
|
|
s_json
|
|
);
|
|
rsps := Nil;
|
|
rqt := TMemoryStream.Create();
|
|
Try
|
|
rsps := TMemoryStream.Create();
|
|
ASerializer.SaveToStream(rqt);
|
|
rqt.Position := 0;
|
|
ATransport.SendAndReceive(rqt,rsps);
|
|
rqt.Clear();
|
|
rsps.Position := 0;
|
|
ASerializer.Clear();
|
|
ASerializer.LoadFromStream(rsps);
|
|
Finally
|
|
rsps.Free();
|
|
rqt.Free();
|
|
End;
|
|
end;
|
|
|
|
procedure RegisterJsonProtocol();
|
|
begin
|
|
GetFormaterRegistry().Register(
|
|
s_json,
|
|
TSimpleItemFactory.Create(TJsonRpcFormatter),
|
|
TSimpleItemFactory.Create(TJsonRpcCallMaker)
|
|
);
|
|
end;
|
|
|
|
{ TJsonRpcSequencedIdManager }
|
|
|
|
constructor TJsonRpcSequencedIdManager.Create();
|
|
begin
|
|
FIdSequenceLock := TCriticalSection.Create();
|
|
end;
|
|
|
|
destructor TJsonRpcSequencedIdManager.Destroy();
|
|
begin
|
|
FreeAndNil(FIdSequenceLock);
|
|
inherited Destroy();
|
|
end;
|
|
|
|
function TJsonRpcSequencedIdManager.GetNewID() : PtrInt;
|
|
begin
|
|
FIdSequenceLock.Acquire();
|
|
try
|
|
Inc(FIdSequence);
|
|
Result := FIdSequence;
|
|
finally
|
|
FIdSequenceLock.Release();
|
|
end;
|
|
end;
|
|
|
|
initialization
|
|
SetIdManager(TJsonRpcSequencedIdManager.Create());
|
|
RegisterJsonProtocol();
|
|
|
|
finalization
|
|
FreeAndNil(FIdManager);
|
|
|
|
end.
|