logo.png
mORMot2 API Reference

mormot.core.interfaces.pas unit

Purpose: Framework Core Low-Level Interface/SOLID Processing
- this unit is a part of the Open Source Synopse mORMot framework 2, licensed under a MPL/GPL/LGPL three license - see LICENSE.md

1.1. Units used in the mormot.core.interfaces unit

Unit NameDescription
mormot.core.baseFramework Core Shared Types and RTL-like Functions
mormot.core.buffersFramework Core Low-Level Memory Buffer Process
mormot.core.dataFramework Core Low-Level Data Processing Functions
mormot.core.jsonFramework Core Low-Level JSON Processing
mormot.core.logFramework Core Logging
mormot.core.osFramework Core Low-Level Wrappers to the Operating-System API
mormot.core.rttiFramework Core Low-Level Cross-Compiler RTTI Definitions
mormot.core.testFramework Core Unit and Regression Testing
mormot.core.textFramework Core Low-Level Text Processing
mormot.core.threadsFramework Core Multi-Threading Support
mormot.core.unicodeFramework Core Low-Level Unicode UTF-8 UTF-16 Ansi Conversion
mormot.core.variantsFramework Core Low-Level Variants / TDocVariant process

1.2. mormot.core.interfaces class hierarchy

TOnInterfaceStubExecuteParamsAbstractTOnInterfaceStubExecuteParamsVariantTOnInterfaceStubExecuteParamsJsonTObjectTInterfaceStubRulesTInterfaceStubLogTInterfaceResolverTInterfaceMethodExecuteRawTInterfaceMethodArgumentTInterfaceMethodTInterfaceFactoryTInterfaceMockTInterfaceMockSpyTInterfaceStubTInterfaceResolverListTInterfaceResolverInjectedTInterfaceResolverForSingleInterfaceTInterfaceMethodExecuteTInterfaceMethodExecuteCachedTInterfaceFactoryRttiTInterfaceFactoryGeneratedTInterfacedObjectWithCustomCreateTInjectableObjectTInterfacedObjectFakeTInterfacedObjectFakeCallbackTInterfacedObjectFakeRawTInterfacedObjectESynExceptionEInterfaceResolverEInterfaceFactoryEInterfaceStub
mormot.core.interfaces class hierarchy

1.3. Objects implemented in the mormot.core.interfaces unit

ObjectsDescription
EInterfaceFactoryException dedicated to interface factory, used e.g. for services and mock/stubs
EInterfaceResolverException raised in case of Dependency Injection (aka IoC) issue
EInterfaceStubException class raised during dependency stubing/mocking process
TFakeCallContextRaw execution context for TInterfacedObjectFakeRaw.FakeCall*() methods
TFakeCallStackMap the stack memory layout at TInterfacedObjectFake.FakeCall()
TInjectableObjectAny service implementation class could inherit from this class to allow dependency injection aka SOLID DI/IoC by the framework
TInterfacedObjectFakeInstances of this class will emulate a given interface over JSON content
TInterfacedObjectFakeCallbackAbstract class defining a FakeInvoke() virtual method via a TOnFakeInstanceInvoke signature
TInterfacedObjectFakeRawAbstract class handling a generic interface implementation class
TInterfaceFactoryClass handling interface RTTI and fake implementation class
TInterfaceFactoryArgumentIndex-based reference to one TInterfaceFactory argument
TInterfaceFactoryGeneratedClass handling interface implementation generated from source
TInterfaceFactoryRttiClass handling interface RTTI and fake implementation class
TInterfaceMethodDescribe an interface-based service provider method
TInterfaceMethodArgumentDescribe a service provider method argument
TInterfaceMethodExecuteExecute a method of a TInterfacedObject instance, from/to JSON
TInterfaceMethodExecuteCachedReusable interface method execution from/to JSON
TInterfaceMethodExecuteRawAbtract execution of a TInterfacedObject method
TInterfaceMockUsed to mock an interface implementation via expect-run-verify pattern
TInterfaceMockSpyUsed to mock an interface implementation via run-verify pattern
TInterfaceResolverAbstract factory class allowing to call interface resolution in cascade
TInterfaceResolverForSingleInterfaceAbstract factory class targetting a single kind of interface
TInterfaceResolverInjectedAbstract factory class targetting any kind of interface
TInterfaceResolverListRegister a thread-safe list of classes to implement some interfaces
TInterfaceResolverListEntryHow TInterfaceResolverList store one interface/class
TInterfaceStubUsed to stub an interface implementation
TInterfaceStubLogUsed to keep track of one stubbed method call
TInterfaceStubRuleDefine a mocking / stubing rule used internally by TInterfaceStub
TInterfaceStubRulesDefine the rules for a given method as used internally by TInterfaceStub
TOnInterfaceStubExecuteParamsAbstractAbstract parameters used by TInterfaceStub.Executes() events callbacks
TOnInterfaceStubExecuteParamsJsonParameters used by TInterfaceStub.Executes() events callbacks as JSON
TOnInterfaceStubExecuteParamsVariantParameters used by TInterfaceStub.Executes() events callbacks as Variant
TServiceCustomAnswerA record type to be used as result for a function method for custom content for interface-based services

1.3.1. TInterfaceMethodArgument

TInterfaceMethodArgument = object(TObject)

Describe a service provider method argument


ArgRtti: TRttiJson;

The low-level RTTI information of this argument
- use ArgRtti.Info to retrieve the TypeInfo() of this argument


ArgTypeName: PShortString;

The type name, as declared in object pascal


FPRegisterIdent: byte;

Specify if a floating-point argument is passed as register
- i386/x87: contains always 0
- x86_64: 1 for XMM0, 2 for XMM1, , ..., 8 for XMM7
- ARMHF: 1 for D0, 2 for D1, ..., 8 for D7
- AARCH64: 1 for V0, 2 for V1, ..., 8 for V7


IndexVar: byte;

Index of the associated variable in the local array[ArgsUsedCount[]]


InStackOffset: smallint;

Byte offset in the CPU stack of this argument (16-bit)
- may be -1 if pure register parameter with no backup on stack (x86)


OffsetAsValue: cardinal;

64-bit aligned position in TInterfaceMethod.ArgsSizeAsValue memory


ParamName: PShortString;

The argument name, as declared in object pascal


RegisterIdent: byte;

Specify if the argument is passed as register
- contains 0 if parameter is not a register
- i386: 1 for EAX, 2 for EDX and 3 for ECX registers
- x86_64: 1=RCX/RDI 2=RDX/RSI 3=R8/RDX 4=R9/RCX, with stack backing store
- ARM: 1=R0 2=R1 3=R2 4=R3, with a backing store on the stack
- AARCH64: 1=X0 2=X1, ..., 8=X7, with a backing store on the stack


SizeInStack: byte;

Size (in bytes) of this argument on the stack


ValueDirection: TInterfaceMethodValueDirection;

The variable direction as defined at code level


ValueKindAsm: TInterfaceMethodValueAsm;

How the variable is to be passed at asm level


ValueType: TInterfaceMethodValueType;

We do not handle all kind of object pascal variables


ValueVar: TInterfaceMethodValueVar;

How the variable may be stored


function SetFromJson(var Ctxt: TJsonParserContext; Method: PInterfaceMethod; V: pointer; Error: PShortString): boolean;

Unserialize a JSON value into this argument


procedure AddAsVariant(var Dest: TDocVariantData; V: pointer);

Add a value into a TDocVariant object or array
- Dest should already have set its Kind to either dvObject or dvArray


procedure AddDefaultJson(WR: TJsonWriter);

Append the default JSON value corresponding to this argument
- includes a pending ','


procedure AddJson(WR: TJsonWriter; V: pointer; ObjectOptions: TTextWriterWriteObjectOptions = [woDontStoreDefault]);

Append the JSON value corresponding to this argument


procedure AddJsonEscaped(WR: TJsonWriter; V: pointer);

Append the value corresponding to this argument as within a JSON string
- will escape any JSON string character, and include a pending ','


procedure AddValueJson(WR: TJsonWriter; const Value: RawUtf8);

Append the JSON value corresponding to this argument, from its text value
- includes a pending ','


procedure FixValue(var Value: variant);

Normalize a value containing one input or output argument
- sets and enumerates will be translated to strings (also in embedded objects and T*ObjArray)


procedure FixValueAndAddToObject(const Value: variant; var DestDoc: TDocVariantData);

Normalize a value containing one input or output argument, and add it to a destination variant Document
- sets and enumerates will be translated to strings (also in embedded objects and T*ObjArray)


procedure SerializeToContract(WR: TJsonWriter);

Serialize the argument into the TServiceContainer.Contract JSON format
- non standard types (e.g. class, enumerate, dynamic array or record) are identified by their type identifier - so contract does not extend up to the content of such high-level structures


1.3.2. TInterfaceMethod

TInterfaceMethod = object(TObject)

Describe an interface-based service provider method


Args: TInterfaceMethodArgumentDynArray;

Describe expected method arguments
- Args[0] always is imvSelf
- if method is a function, an additional imdResult argument is appended


ArgsInFirst: shortint;

The index of the first const / var argument in Args[] (signed 8-bit)


ArgsInLast: shortint;

The index of the last const / var argument in Args[] (signed 8-bit)


ArgsInputIsOctetStream: boolean;

True if there is a single input parameter as RawByteString/RawBlob
- TRestRoutingRest.ExecuteSoaByInterface will identify binary input with mime-type 'application/octet-stream' as expected


ArgsInputValuesCount: byte;

The number of const / var parameters in Args[]
- i.e. the number of elements in the input JSON array


ArgsManagedCount: byte;

How manual stack initialization arguments are defined
- set for Args[].ValueVar >= imvvRawUtf8


ArgsManagedFirst: shortint;

The index of the first argument expecting manual stack initialization
- set for Args[].ValueVar >= imvvRawUtf8


ArgsNotResultLast: shortint;

The index of the last argument in Args[], excepting result (signed 8-bit)


ArgsOutFirst: shortint;

The index of the first var / out / result argument in Args[] (signed 8-bit)


ArgsOutLast: shortint;

The index of the last var / out / result argument in Args[] (signed 8-bit)


ArgsOutNotResultLast: shortint;

The index of the last var / out argument in Args[] (signed 8-bit)


ArgsOutputValuesCount: byte;

The number of var / out parameters + in Args[]
- i.e. the number of elements in the output JSON array or object


ArgsResultIndex: shortint;

The index of the result pseudo-argument in Args[] (signed 8-bit)
- is -1 if the method is defined as a procedure (not a function)


ArgsResultIsServiceCustomAnswer: boolean;

True if the result is a TServiceCustomAnswer record
- that is, a custom Header+Content BLOB transfert, not a JSON object


ArgsResultIsServiceCustomStatus: boolean;

True if the result is a TServiceCustomStatus 32-bit integer
- that is, a custom HTTP status


ArgsSizeAsValue: cardinal;

64-bit aligned cumulative size for all arguments values
- follow Args[].OffsetAsValue distribution


ArgsSizeInStack: word;

Needed CPU stack size (in bytes) for all arguments
- under x64, does not include the backup space for the four registers


ArgsUsed: TInterfaceMethodValueTypes;

Contains all used kind of arguments


ArgsUsedCount: array[TInterfaceMethodValueVar] of byte;

Contains the count of variables for all used kind of arguments


DefaultResult: RawUtf8;

The method default result, formatted as a JSON array
- example of content may be '[]' for a procedure or '[0]' for a function
- any var/out and potential function result will be set as a JSON array of values, with 0 for numerical values, "" for textual values, false for booleans, [] for dynamic arrays, a void record serialized as expected (including customized serialization) and null for objects


ExecutionMethodIndex: byte;

Method index in the original (non emulated) interface
- our custom methods start at index 3 (RESERVED_VTABLE_SLOTS), since QueryInterface, _AddRef, and _Release are always defined by default
- so it maps TServiceFactory.Interface.Methods[ExecutionMethodIndex-3]


HasSpiParams: TInterfaceMethodValueDirections;

The directions of arguments with SPI parameters defined


HierarchyLevel: byte;

Is 0 for the root interface, 1..n for all inherited interfaces


InterfaceDotMethodName: RawUtf8;

The fully qualified dotted method name, including the interface name
- as used by TServiceContainerInterfaceMethod.InterfaceDotMethodName
- match the URI fullpath name, e.g. 'Calculator.Add'


IsInherited: boolean;

TRUE if the method is inherited from another parent interface


Uri: RawUtf8;

The method URI, i.e. the method name
- as declared in object pascal code, e.g. 'Add' for ICalculator.Add
- this property value is hashed internally for faster access


function ArgIndex(ArgName: PUtf8Char; ArgNameLen: integer; Input: boolean): PtrInt;

Retrieve an argument index in Args[] from its name
- search is case insensitive
- if Input is TRUE, will search within const / var arguments
- if Input is FALSE, will search within var / out / result arguments
- returns -1 if not found


function ArgNextInput(var arg: integer): boolean;

Find the next input (const / var) argument index in Args[]
- returns true if arg is the new value, false otherwise


function ArgNextOutput(var arg: integer): boolean;

Find the next output (var / out / result) argument index in Args[]
- returns true if arg is the new value, false otherwise


function ArgsArrayToObject(P: PUtf8Char; Input: boolean): RawUtf8;

Convert parameters encoded as a JSON array into a JSON object
- if Input is TRUE, will handle const / var arguments
- if Input is FALSE, will handle var / out / result arguments


function ArgsCommandLineToObject(P: PUtf8Char; Input: boolean; RaiseExceptionOnUnknownParam: boolean = false): RawUtf8;

Convert parameters encoded as name=value or name='"value"' or name='{somejson}' into a JSON object
- on Windows, use double-quotes ("") anywhere you expect single-quotes (")
- as expected e.g. from a command line tool
- if Input is TRUE, will handle const / var arguments
- if Input is FALSE, will handle var / out / result arguments


function ArgsNames(Input: boolean): TRawUtf8DynArray;

Returns a dynamic array list of all parameter names
- if Input is TRUE, will handle const / var arguments
- if Input is FALSE, will handle var / out / result arguments


procedure ArgsAsDocVariantFix(var ArgsObject: TDocVariantData; Input: boolean);

Normalize a TDocVariant containing the input or output arguments values
- "normalization" will ensure sets and enums are seralized as text
- if Input is TRUE, will handle const / var arguments
- if Input is FALSE, will handle var / out / result arguments


procedure ArgsAsDocVariantObject(const ArgsParams: TDocVariantData; var ArgsObject: TDocVariantData; Input: boolean);

Convert a TDocVariant array containing the input or output arguments values in order, into an object with named parameters
- here sets and enums will keep their current values, mainly numerical
- if Input is TRUE, will handle const / var arguments
- if Input is FALSE, will handle var / out / result arguments


procedure ArgsStackAsDocVariant(Values: PPointerArray; out Dest: TDocVariantData; Input: boolean);

Computes a TDocVariant containing the input or output arguments values
- Values[] should point to the input/output raw binary values, as stored in TInterfaceMethodExecute.Values during execution


procedure ArgsValuesAsDocVariant(Kind: TInterfaceMethodParamsDocVariantKind; out Dest: TDocVariantData; const Values: TVariantDynArray; Input: boolean; Options: TDocVariantOptions = [dvoReturnNullForUnknownProperty, dvoValueCopiedByReference]);

Computes a TDocVariant containing the input or output arguments values
- Values[] should contain the input/output raw values as variant
- Kind will specify the expected returned document layout


1.3.3. EInterfaceFactory

EInterfaceFactory = class(ESynException)

Exception dedicated to interface factory, used e.g. for services and mock/stubs


1.3.4. TInterfaceFactoryArgument

TInterfaceFactoryArgument = record

Index-based reference to one TInterfaceFactory argument


ArgIndex: byte;

The index of the method argument in TInterfaceFactory.Methods[].Args[]


MethodIndex: byte;

The index of the method argument in TInterfaceFactory.Methods[]


1.3.5. TInterfaceFactory

TInterfaceFactory = class(TObject)

Class handling interface RTTI and fake implementation class
- an internal JIT compiler will generate the raw asm opcodes to redirect any interface execution into a fake class
- a thread-safe global list of such class instances is implemented to cache information for better speed: use class function TInterfaceFactory.Get() and not manual TInterfaceFactory.Create / Free
- if you want to search the interfaces by name or TGuid, call once Get(TypeInfo(IMyInterface)) or RegisterInterfaces() for proper registration
- will use TInterfaceFactoryRtti classes generated from compiler RTTI


constructor Create(aInterface: PRttiInfo);

Initialize the internal properties from the supplied interface RTTI
- it will check and retrieve all methods of the supplied interface, and prepare all internal structures for later use
- do not call this constructor directly, but TInterfaceFactory.Get()


function CheckMethodIndex(aMethodName: PUtf8Char): integer; overload;

Find the index of a particular method in internal Methods[] list
- won't find the default AddRef/Release/QueryInterface methods
- will raise an EInterfaceFactory if the method is not known


function CheckMethodIndex(const aMethodName: RawUtf8): PtrInt; overload;

Find the index of a particular method in internal Methods[] list
- won't find the default AddRef/Release/QueryInterface methods
- will raise an EInterfaceFactory if the method is not known


function FindFullMethodIndex(const aFullMethodName: RawUtf8; alsoSearchExactMethodName: boolean = false): integer;

Find the index of a particular interface.method in internal Methods[] list
- will search for a match against Methods[].InterfaceDotMethodName property
- won't find the default AddRef/Release/QueryInterface methods
- will return -1 if the method is not known


function FindMethod(const aMethodName: RawUtf8): PInterfaceMethod;

Find a particular method in internal Methods[] list
- just a wrapper around FindMethodIndex() returing a PInterfaceMethod
- will return nil if the method is not known


function FindMethodIndex(const aMethodName: RawUtf8): PtrInt;

Find the index of a particular method in internal Methods[] list
- will search for a match against Methods[].Uri property
- won't find the default AddRef/Release/QueryInterface methods, nor the _free_/_instance_/... pseudo-methods
- will return -1 if the method is not known
- if aMethodName does not have an exact method match, it will try with a trailing underscore, so that e.g. /service/start will match IService._Start()


class function Get(aInterface: PRttiInfo): TInterfaceFactory; overload;

This is the main entry point to the global interface factory cache
- access to this method is thread-safe
- this method will also register the class to further retrieval


class function Get(const aInterfaceName: RawUtf8): TInterfaceFactory; overload;

Retrieve an interface factory from cache, from its name (e.g. 'IMyInterface')
- access to this method is thread-safe
- you shall have registered the interface by a previous call to the overloaded Get(TypeInfo(IMyInterface)) method or RegisterInterfaces()
- if the supplied TGuid has not been previously registered, returns nil


class function Get(const aGuid: TGuid): TInterfaceFactory; overload;

Retrieve an interface factory from cache, from its TGuid
- access to this method is thread-safe
- you shall have registered the interface by a previous call to the overloaded Get(TypeInfo(IMyInterface)) method or RegisterInterfaces()
- if the supplied TGuid has not been previously registered, returns nil


function GetFullMethodName(aMethodIndex: integer): RawUtf8;

Returns the full 'Interface.MethodName' text, from a method index
- the method index should start at 0 for _free_/_contract_/_signature_ pseudo-methods, and start at index 3 for real Methods[]
- will return plain 'Interface' text, if aMethodIndex is incorrect


function GetMethodName(MethodIndex: integer): RawUtf8;

Returns the method name from its method index
- the method index should start at 0 for _free_/_contract_/_signature_ pseudo-methods, and start at index 3 for real Methods[]


class function GetUsedInterfaces: TSynObjectListLightLocked;

Returns the list of all declared TInterfaceFactory
- as used by SOA and mocking/stubing features of this unit


class function Guid2TypeInfo(const aGuids: array of TGuid): PRttiInfoDynArray; overload;

Could be used to retrieve an array of TypeInfo() from their Guid


class function Guid2TypeInfo(const aGuid: TGuid): PRttiInfo; overload;

Could be used to retrieve an array of TypeInfo() from their Guid


class procedure AddToObjArray(var Obj: TInterfaceFactoryObjArray; const aGuids: array of TGuid);

Add some TInterfaceFactory instances from their Guid


procedure CheckMethodIndexes(const aMethodName: array of RawUtf8; aSetAllIfNone: boolean; out aBits: TInterfaceFactoryMethodBits);

Set the Methods[] indexes bit from some methods names
- won't find the default AddRef/Release/QueryInterface methods
- will raise an EInterfaceFactory if the method is not known


class procedure RegisterInterfaces(const aInterfaces: array of PRttiInfo);

Register one or several interfaces to the global interface factory cache
- so that you can use TInterfaceFactory.Get(aGuid) or Get(aName)


class procedure RegisterUnsafeSpiType(const Types: array of PRttiInfo);

Register some TypeInfo() containing unsafe parameter values
- i.e. any RTTI type containing Sensitive Personal Information, e.g. a bank card number or a plain password
- such values will force associated values to be ignored during loging, as a more tuned alternative to optNoLogInput or optNoLogOutput


property ArgUsed: TInterfaceFactoryPerArgumentDynArray read fArgUsed;

Reference all known interface arguments per value type


property Contract: RawUtf8 read fContract;

The service contract as a JSON array


property DocVariantOptions: TDocVariantOptions read fDocVariantOptions write fDocVariantOptions;

How this interface will work with variants (including TDocVariant)
- by default, contains JSON_FAST_FLOAT for best performance - i.e. [dvoReturnNullForUnknownProperty,dvoValueCopiedByReference, dvoAllowDoubleValue]


property InterfaceIID: TGuid read fInterfaceIID;

The registered Interface Guid


property InterfaceName: RawUtf8 read fInterfaceName;

Will return the interface name, e.g. 'ICalculator'
- published property to be serializable as JSON e.g. for debbuging info


property InterfaceRtti: TRttiJson read fInterfaceRtti;

The registered Interface high-level compiler RTTI type


property InterfaceTypeInfo: PRttiInfo read fInterfaceTypeInfo;

The registered Interface low-level compiler RTTI type


property InterfaceUri: RawUtf8 read fInterfaceUri write fInterfaceUri;

The interface name, without its initial 'I'
- e.g. ICalculator -> 'Calculator'


property JsonParserOptions: TJsonParserOptions read fJsonParserOptions write fJsonParserOptions;

How this interface will process its JSON parsing
- by default, contains JSONPARSER_SERVICE very relaxed parsing options


property MethodIndexCallbackReleased: integer read fMethodIndexCallbackReleased;

Identifies a CallbackReleased() method in this interface
- i.e. the index in Methods[] of the following signature:

 procedure CallbackReleased(const callback: IInvokable; const interfaceName: RawUtf8);

- this method will be called e.g. by TInterfacedCallback.Destroy, when a callback is released on the client side so that you may be able e.g. to unsubscribe the callback from an interface list (via InterfaceArrayDelete)
- contains -1 if no such method do exist in the interface definition


property MethodIndexCurrentFrameCallback: integer read fMethodIndexCurrentFrameCallback;

Identifies a CurrentFrame() method in this interface
- i.e. the index in Methods[] of the following signature:

 procedure CurrentFrame(isLast: boolean);

- this method will be called e.g. by TRestHttpClientWebsockets.CallbackRequest for interface callbacks in case of WebSockets jumbo frames, to allow e.g. faster database access via a batch
- contains -1 if no such method do exist in the interface definition


property Methods: TInterfaceMethodDynArray read fMethods;

The declared internal methods
- list does not contain default AddRef/Release/QueryInterface methods
- nor the _free_/_contract_/_signature_ pseudo-methods


property MethodsCount: integer read fMethodsCount;

The number of internal methods
- does not include the default AddRef/Release/QueryInterface methods
- nor the _free_/_contract_/_signature_ pseudo-methods: so you should add SERVICE_PSEUDO_METHOD_COUNT to compute the regular MethodIndex


1.3.6. TInterfaceFactoryRtti

TInterfaceFactoryRtti = class(TInterfaceFactory)

Class handling interface RTTI and fake implementation class
- this class only exists for Delphi 6 and up, and newer FPC, which has the expected RTTI - see http://bugs.freepascal.org/view.php?id=26774


1.3.7. TInterfaceFactoryGenerated

TInterfaceFactoryGenerated = class(TInterfaceFactory)

Class handling interface implementation generated from source
- this class targets oldest FPC, which did not generate the expected RTTI - see http://bugs.freepascal.org/view.php?id=26774
- mormot.soa.codegen.pas will generate a new inherited class, overriding abstract AddMethodsFromTypeInfo() to define the interface methods


class procedure RegisterInterface(aInterface: PRttiInfo); virtual;

Register one interface type definition from the current class
- will be called by mormot.soa.codegen generated code, in initialization section, so that the needed type information will be available


1.3.8. TServiceCustomAnswer

TServiceCustomAnswer = record

A record type to be used as result for a function method for custom content for interface-based services
- all answers are pure JSON object by default: using this kind of record as result will allow a response of any type (e.g. binary, HTML or text)
- this kind of answer will be understood by our TServiceContainerClient implementation, and it may be used with plain AJAX or HTML requests (via POST), to retrieve some custom content


Content: RawByteString;

The response body
- corresponding to the response type, as defined in Header


Header: RawUtf8;

Mandatory response type, as encoded in the HTTP header
- set the response mime-type - use e.g. JSON_CONTENT_TYPE_HEADER_VAR TEXT_CONTENT_TYPE_HEADER or BINARY_CONTENT_TYPE_HEADER constants or GetMimeContentType() function
- if this field is not set, then JSON_CONTENT_TYPE_HEADER will be forced


Status: cardinal;

The HTTP response code
- if not overriden, will default to HTTP_SUCCESS = 200 on server side
- on client side, will always contain HTTP_SUCCESS = 200 on success, or any error should be handled as expected by the caller (e.g. using TServiceFactoryClient.GetErrorMessage for decoding REST/SOA errors)


1.3.9. EInterfaceResolver

EInterfaceResolver = class(ESynException)

Exception raised in case of Dependency Injection (aka IoC) issue


1.3.10. TInterfaceResolver

TInterfaceResolver = class(TObject)

Abstract factory class allowing to call interface resolution in cascade
- you can inherit from this class to chain the TryResolve() calls so that several kind of implementations may be asked by a TInjectableObject, e.g. TInterfaceStub, TServiceContainer or TDDDRepositoryRestObjectMapping
- this will implement factory pattern, as a safe and thread-safe DI/IoC


function Implements(aInterface: PRttiInfo): boolean; virtual;

Override this method check if this instance implements aInterface RTTI
- this default implementation will call TryResolve() on a local IInterface which is somewhat slow, and should better be overriden


function Resolve(const aGuid: TGuid; out Obj; aRaiseIfNotFound: ESynExceptionClass = nil): boolean; overload;

Can be used to perform an DI/IoC for a given interface
- you shall have registered the interface TGuid by a previous call to

 TInterfaceFactory.RegisterInterfaces([TypeInfo(ICalculator),...])

- returns TRUE and set the Obj variable with a matching instance
- returns FALSE (or raise aRaiseIfNotFound) if aGuid is not available
- can be used as such to resolve an ICalculator interface:

 var calc: ICalculator;
 begin
   if ServiceContainer.Resolve(ICalculator,cal) then
   ... use calc methods

function Resolve(aInterface: PRttiInfo; out Obj): boolean; overload;

Can be used to perform an DI/IoC for a given interface
- will search for the supplied interface to its internal list of resolvers
- returns TRUE and set the Obj variable with a matching instance
- can be used as such to resolve an ICalculator interface:

 var calc: ICalculator;
 begin
   if Catalog.Resolve(TypeInfo(ICalculator),calc) then
   ... use calc methods

procedure Resolve(const aInterfaces: array of TGuid; const aObjs: array of pointer; aRaiseExceptionIfNotFound: boolean = true); overload;

Can be used to perform several DI/IoC for a given set of interfaces
- here interfaces and instances are provided as TGuid and @Instance
- you shall have registered the interface TGuid by a previous call to

 TInterfaceFactory.RegisterInterfaces([TypeInfo(ICalculator),...])

- raise an EServiceException if any interface can't be resolved, unless aRaiseExceptionIfNotFound is set to FALSE


procedure ResolveByPair(const aInterfaceObjPairs: array of pointer; aRaiseExceptionIfNotFound: boolean = true);

Can be used to perform several DI/IoC for a given set of interfaces
- here interfaces and instances are provided as TypeInfo,@Instance pairs
- raise an EServiceException if any interface can't be resolved, unless aRaiseExceptionIfNotFound is set to FALSE


1.3.11. TInterfaceResolverForSingleInterface

TInterfaceResolverForSingleInterface = class(TInterfaceResolver)

Abstract factory class targetting a single kind of interface


constructor Create(const aInterface: TGuid; aImplementation: TInterfacedObjectClass); overload;

This overriden constructor will check and store the supplied class to implement an interface by TGuid


constructor Create(aInterface: PRttiInfo; aImplementation: TInterfacedObjectClass); overload;

This overriden constructor will check and store the supplied class to implement an interface


function GetOneInstance(out Obj): boolean;

You can use this method to resolve the interface as a new instance


function Implements(aInterface: PRttiInfo): boolean; override;

Check if can resolve the supplied interface RTTI


property ImplementationClass: RawUtf8 read GetImplementationName;

The class name which will implement each repository instance


1.3.12. TInterfaceResolverListEntry

TInterfaceResolverListEntry = record

How TInterfaceResolverList store one interface/class


ImplementationClass: TRttiCustom;

The associated RTTI - mainly used to call its ClassNewInstance method


Instance: IInterface;

Shared instance
- will be released with the TInterfaceResolverListEntries array


InterfaceEntry: PInterfaceEntry;

Low-level interface VMT information for fast creation


TypeInfo: PRttiInfo;

Contains TypeInfo(ISomeInterface)


1.3.13. TInterfaceResolverList

TInterfaceResolverList = class(TInterfaceResolver)

Register a thread-safe list of classes to implement some interfaces
- as used e.g. by TInterfaceResolverInjected.RegisterGlobal()


function Implements(aInterface: PRttiInfo): boolean; override;

Check if a given interface can be resolved, from its RTTI


procedure Add(aInterface: PRttiInfo; aImplementation: TInterfacedObject); overload;

Register a given implementation class instance for an interface
- the shared aImplementation instance will be returned for each resolution
- aImplementation will be owned by the internal registration list


procedure Add(aInterface: PRttiInfo; aImplementationClass: TInterfacedObjectClass); overload;

Register a given implementaiton class for an interface
- a new aImplementationClass instance will be created for each resolution


procedure Delete(aInterface: PRttiInfo);

Unregister a given implementation class for an interface
- raise EInterfaceResolver if an TInterfacedObject instance was registered


property Entry: TInterfaceResolverListEntries read fEntry;

Low-level access to the internal registered interface/class list
- should be protected via the Safe locking methods


property OnCreateInstance: TOnResolverCreateInstance read fOnCreateInstance write fOnCreateInstance;

Is called when a new aImplementationClass instance has been created


property Safe: TRWLightLock read fSafe;

Low-level access to the internal lock for thread-safety


1.3.14. TInterfaceResolverInjected

TInterfaceResolverInjected = class(TInterfaceResolver)

Abstract factory class targetting any kind of interface
- you can inherit from this class to customize dependency injection (DI/IoC), defining the resolution via InjectStub/InjectResolver/InjectInstance methods, and doing the instance resolution using the overloaded Resolve*() methods
- TServiceContainer will inherit from this class, as the main entry point for interface-based services of the framework (via TRest.Services)
- you can use RegisterGlobal() class method to define some process-wide DI


destructor Destroy; override;

Release all used instances
- including all TInterfaceStub instances as specified to Inject(aStubsByGuid)
- will call _Release on all TInterfacedObject dependencies


function Implements(aInterface: PRttiInfo): boolean; override;

Check if a given interface can be resolved, from its RTTI


procedure DeleteResolver(aResolver: TInterfaceResolver);

Delete a previously registered resolver
- aResolver can be re-registered afterwards


procedure InjectInstance(const aDependencies: array of TInterfacedObject); overload; virtual;

Prepare and setup interface DI/IoC resolution from a TInterfacedObject instance
- any TInterfacedObject declared as dependency will have its reference count increased, and decreased in Destroy


procedure InjectResolver(const aOtherResolvers: array of TInterfaceResolver; OwnOtherResolvers: boolean = false); overload; virtual;

Prepare and setup interface DI/IoC resolution with TInterfaceResolver kind of factory
- e.g. a customized TInterfaceStub/TInterfaceMock, a TServiceContainer, a TDDDRepositoryRestObjectMapping or any factory class
- by default, only TInterfaceStub/TInterfaceMock will be owned by this instance, and released by Destroy - unless you set OwnOtherResolvers


procedure InjectStub(const aStubsByGuid: array of TGuid); overload; virtual;

Prepare and setup interface DI/IoC resolution with some blank TInterfaceStub specified by their TGuid


class procedure RegisterGlobal(aInterface: PRttiInfo; aImplementation: TInterfacedObject); overload;

Define a global instance for interface resolution
- most of the time, you will need a local DI/IoC resolution list; but you may use this method to register a set of shared and global resolution patterns, common to the whole injection process
- the supplied instance will be owned by the global list (incrementing its internal reference count), until it will be released via

 RegisterGlobalDelete()

- the supplied instance will be freed in the finalization of this unit, if not previously released via RegisterGlobalDelete()


class procedure RegisterGlobal(aInterface: PRttiInfo; aImplementationClass: TInterfacedObjectClass); overload;

Define a global class type for interface resolution
- most of the time, you will need a local DI/IoC resolution list; but you may use this method to register a set of shared and global resolution patterns, common to the whole injection process
- by default, TAutoLocker and TLockedDocVariant will be registered by this unit to implement IAutoLocker and ILockedDocVariant interfaces


class procedure RegisterGlobalDelete(aInterface: PRttiInfo);

Undefine a global instance for interface resolution
- you can unregister a given instance previously defined via

 RegisterGlobal(aInterface,aImplementation)

- if you do not call RegisterGlobalDelete(), the remaning instances will be freed in the finalization of this unit


1.3.15. TInjectableObject

TInjectableObject = class(TInterfacedObjectWithCustomCreate)

Any service implementation class could inherit from this class to allow dependency injection aka SOLID DI/IoC by the framework
- once created, the framework will call AddResolver() member, so that its Resolve*() methods could be used to inject any needed dependency for lazy dependency resolution (e.g. within a public property getter)
- any interface published property will also be automatically injected
- if you implement a SOA service with this class, TRestServer.Services will be auto-injected via TServiceFactoryServer.CreateInstance()


constructor CreateInjected(const aStubsByGuid: array of TGuid; const aOtherResolvers: array of TInterfaceResolver; const aDependencies: array of TInterfacedObject; aRaiseEServiceExceptionIfNotFound: boolean = true); virtual;

Initialize an instance, defining one or several mean of dependency resolution
- simple TInterfaceStub could be created directly from their TGuid, then any kind of DI/IoC resolver instances could be specified, i.e. either customized TInterfaceStub/TInterfaceMock, a TServiceContainer or a TDDDRepositoryRestObjectMapping, and then any TInterfacedObject instance will be used during dependency resolution:

 procedure TMyTestCase.OneTestCaseMethod;
 var Test: IServiceToBeTested;
 begin
   Test := TServiceToBeTested.CreateInjected(
     [ICalculator],
     [TInterfaceMock.Create(IPersistence,self).
       ExpectsCount('SaveItem',qoEqualTo,1),
      RestInstance.Services],
     [AnyInterfacedObject]);
   ...

- note that all the injected stubs/mocks instances will be owned by the TInjectableObject, and therefore released with it
- any TInterfacedObject declared as dependency will have its reference count increased, and decreased in Destroy
- once DI/IoC is defined, will call the AutoResolve() protected method


constructor CreateWithResolver(aResolver: TInterfaceResolver; aRaiseEServiceExceptionIfNotFound: boolean = true); virtual;

Initialize an instance, defining one dependency resolver
- the resolver may be e.g. a TServiceContainer
- once the DI/IoC is defined, will call the AutoResolve() protected method
- as called by TServiceFactoryServer.CreateInstance


destructor Destroy; override;

Release all used instances
- including all TInterfaceStub instances as specified to CreateInjected()


procedure Resolve(const aInterfaces: array of TGuid; const aObjs: array of pointer); overload;

Can be used to perform several DI/IoC for a given set of interfaces
- here interfaces and instances are provided as TGuid and pointers


procedure Resolve(aInterface: PRttiInfo; out Obj); overload;

Can be used to perform an DI/IoC for a given interface type information


procedure Resolve(const aGuid: TGuid; out Obj); overload;

Can be used to perform an DI/IoC for a given interface TGuid


procedure ResolveByPair(const aInterfaceObjPairs: array of pointer);

Can be used to perform several DI/IoC for a given set of interfaces
- here interfaces and instances are provided as TypeInfo,@Instance pairs


property Resolver: TInterfaceResolver read fResolver;

Access to the associated dependency resolver, if any


1.3.16. EInterfaceStub

EInterfaceStub = class(EInterfaceFactory)

Exception class raised during dependency stubing/mocking process


1.3.17. TOnInterfaceStubExecuteParamsAbstract

TOnInterfaceStubExecuteParamsAbstract = class(TObject)

Abstract parameters used by TInterfaceStub.Executes() events callbacks


constructor Create(aSender: TInterfaceStub; aMethod: PInterfaceMethod; const aParams, aEventParams: RawUtf8); virtual;

Constructor of one parameters marshalling instance


procedure Error(const Format: RawUtf8; const Args: array of const); overload;

Call this method if the callback implementation failed


procedure Error(const aErrorMessage: RawUtf8); overload;

Call this method if the callback implementation failed


property EventParams: RawUtf8 read fEventParams;

A custom message, defined at TInterfaceStub.Executes() definition


property Failed: boolean read fFailed;

Low-level flag, set to TRUE if one of the Error() method was called


property Method: PInterfaceMethod read fMethod;

Pointer to the method which is to be executed


property result: RawUtf8 read fResult;

Outgoing values array encoded as JSON
- every var, out parameter or the function result shall be encoded as a JSON array into this variable, in the same order than the stubbed method declaration
- use Returns() method to create the JSON array directly, from an array of values


property Sender: TInterfaceStub read fSender;

The stubbing / mocking generator


property TestCase: TSynTestCase read GetSenderAsMockTestCase;

The mocking generator associated test case
- will raise an exception if the associated Sender generator is not a TInterfaceMock


1.3.18. TOnInterfaceStubExecuteParamsVariant

TOnInterfaceStubExecuteParamsVariant = class(TOnInterfaceStubExecuteParamsAbstract)

Parameters used by TInterfaceStub.Executes() events callbacks as Variant
- this class will expect input and output parameters to specified as variant arrays properties, so is easier (and a bit slower) than the TOnInterfaceStubExecuteParamsJson class


constructor Create(aSender: TInterfaceStub; aMethod: PInterfaceMethod; const aParams, aEventParams: RawUtf8); override;

Constructor of one parameters marshalling instance


function InputAsDocVariant(Kind: TInterfaceMethodParamsDocVariantKind; Options: TDocVariantOptions = [dvoReturnNullForUnknownProperty, dvoValueCopiedByReference]): variant;

Returns the input parameters as a TDocVariant object or array


function OutputAsDocVariant(Kind: TInterfaceMethodParamsDocVariantKind; Options: TDocVariantOptions = [dvoReturnNullForUnknownProperty, dvoValueCopiedByReference]): variant;

Returns the output parameters as a TDocVariant object or array


procedure AddLog(aLog: TSynLogClass; aOutput: boolean; aLevel: TSynLogLevel = sllTrace);

Log the input or output parameters to a log instance


property Input[Index: integer]: variant read GetInput;

Input parameters when calling the method
- order shall follow the method const and var parameters

 Stub.Add(10,20) -> Input[0]=10, Input[1]=20

- if the supplied Index is out of range, an EInterfaceStub will be raised


property Named[const ParamName: RawUtf8]: variant read GetInNamed write SetOutNamed;

Access to input/output parameters when calling the method
- if the supplied name is incorrect, an EInterfaceStub will be raised
- is a bit slower than Input[]/Output[] indexed properties, but easier to work with, and safer in case of method signature change (like parameter add or rename)
- marked as default property, so you can use it e.g. as such:

  procedure TFooTestCase.ExecuteBar(Ctxt: TOnInterfaceStubExecuteParamsVariant);
  begin
    Ctxt['i'] := Ctxt['i']+1;  // i := i+1;
    Ctxt['result'] := 42;      // result := 42;
  end;

to emulate this native implementation:

 function Bar(var i: integer): integer;
 begin
    inc(i);
    result := 42;
  end;

- using this default Named[] property is recommended over the index-based Output[] property
- if an Output[]/Named[] item is not set, a default value will be used


property Output[Index: integer]: variant write SetOutput;

Output parameters returned after method process
- order shall follow the method var, out parameters and the function result (if method is not a procedure)
- if the supplied Index is out of range, an EInterfaceStub will be raised
- can be used as such:

  procedure TFooTestCase.ExecuteBar(Ctxt: TOnInterfaceStubExecuteParamsVariant);
  begin // Input[0]=i
    Ctxt.Output[0] := Ctxt.Input[0]+1;  // i := i+1;
    Ctxt.Output[1] := 42;               // result := 42;
  end; // Output|0]=i, Output[1]=result

to emulate this native implementation:

 function Bar(var i: integer): integer;
 begin
    inc(i);
    result := 42;
  end;

- consider using the safest Named[] property, to avoid parameters index matching issue
- if an Output[]/Named[] item is not set, a default value will be used


property U[const ParamName: RawUtf8]: RawUtf8 read GetInUtf8;

Access to UTF-8 input parameters when calling the method
- if the supplied name is incorrect, an EInterfaceStub will be raised
- is a bit slower than Input[]/Output[] indexed properties, but easier to work with, and safer in case of method signature change (like parameter add or rename)
- slightly easier to use Ctxt.U['str'] than ToUtf8(Ctxt.Named['str'])


1.3.19. TOnInterfaceStubExecuteParamsJson

TOnInterfaceStubExecuteParamsJson = class(TOnInterfaceStubExecuteParamsAbstract)

Parameters used by TInterfaceStub.Executes() events callbacks as JSON
- this class will expect input and output parameters to be encoded as JSON arrays, so is faster than TOnInterfaceStubExecuteParamsVariant


procedure Returns(const ValuesJsonArray: RawUtf8); overload;

A method to return a JSON array of values into result
- expected format is e.g. '[43,42]'


procedure Returns(const Values: array of const); overload;

A method to return an array of values into result
- just a wrapper around JsonEncodeArrayOfConst([...])
- can be used as such:

  procedure TFooTestCase.ExecuteBar(var Ctxt: TOnInterfaceStubExecuteParamsJson);
  begin // Ctxt.Params := '[i]' -> Ctxt.result := '[i+1,42]'
    Ctxt.Returns([GetInteger(pointer(Ctxt.Params))+1,42]);
  end;

to emulate this native implementation:

 function Bar(var i: integer): integer;
 begin
    inc(i);
    result := 42;
  end;

property Params: RawUtf8 read fParams;

Incoming parameters array encoded as JSON array without braces
- order follows the method const and var parameters

 Stub.Add(10,20) -> Params = '10,20';

1.3.20. TInterfaceStubRule

TInterfaceStubRule = record

Define a mocking / stubing rule used internally by TInterfaceStub


ExceptionClass: ExceptClass;

The exception class to be raised
- for TInterfaceStub.Raises(), Values contains Exception.Message


Execute: TMethod;

The event handler to be executed
- for TInterfaceStub.Executes(), Values is transmitted as aResult parameter
- either a TOnInterfaceStubExecuteJson, or a TOnInterfaceStubExecuteVariant


ExpectedPassCount: cardinal;

Expected pass count value set by TInterfaceStub.ExpectsCount()
- value to be compared to the number of times this rule has been executed
- TInterfaceStub/TInterfaceMock will check it in their Destroy destructor, using the comparison stated by ExpectedPassCountOperator


ExpectedPassCountOperator: TInterfaceStubRuleOperator;

Comparison operator set by TInterfaceStub.ExpectsCount()


ExpectedTraceHash: cardinal;

Log trace value set by TInterfaceStub.ExpectsTrace()
- used in conjunction with ExpectedPassCountOperator=ioTraceMatch
- value to be compared to the Hash32() value of the execution log trace
- TInterfaceStub/TInterfaceMock will check it in their Destroy destructor, using the fLogs[] content


Kind: TInterfaceStubRuleKind;

The type of this rule
- isUndefined is used for a TInterfaceStub.ExpectsCount() weak rule


Params: RawUtf8;

Optional expected parameters, serialized as a JSON array
- if equals '', the rule is not parametrized - i.e. it will be the default for this method


RulePassCount: cardinal;

The number of times this rule has been executed


Values: RawUtf8;

Values associated to the rule
- for TInterfaceStub.Executes(), is the aEventParams parameter transmitted to Execute event handler (could be used to e.g. customize the handler)
- for TInterfaceStub.Raises(), is the Exception.Message associated to one ExceptionClass
- for TInterfaceStub.Returns(), is the returned result, serialized as a JSON array (including var / out parameters then any function result)
- for TInterfaceStub.Fails() is the returned error message for TInterfaceStub exception or TInterfaceMock associated test case


1.3.21. TInterfaceStubRules

TInterfaceStubRules = object(TObject)

Define the rules for a given method as used internally by TInterfaceStub


DefaultRule: integer;

Index in Rules[] of the default rule, i.e. the one with Params=''


MethodPassCount: cardinal;

The number of times this method has been executed


Rules: array of TInterfaceStubRule;

The mocking / stubing rules associated to this method


function FindRuleIndex(const aParams: RawUtf8): integer;

Find a rule index from its Params content


function FindStrongRuleIndex(const aParams: RawUtf8): integer;

Find a strong rule index from its Params content


procedure AddRule(Sender: TInterfaceStub; aKind: TInterfaceStubRuleKind; const aParams, aValues: RawUtf8; const aEvent: TNotifyEvent = nil; aExceptionClass: ExceptClass = nil; aExpectedPassCountOperator: TInterfaceStubRuleOperator = ioUndefined; aValue: cardinal = 0);

Register a rule


1.3.22. TInterfaceStubLog

TInterfaceStubLog = object(TObject)

Used to keep track of one stubbed method call


CustomResults: RawUtf8;

Any non default result returned after execution
- if not set (i.e. if equals ''), Method^.DefaultResult has been returned
- if WasError is TRUE, always contain the error message


Method: PInterfaceMethod;

The method called
- a pointer to the existing information in shared TInterfaceFactory


Params: RawUtf8;

The parameters at execution call, as JSON CSV (i.e. array without [ ])


Timestamp64: Int64;

Call timestamp, in milliseconds
- is filled with GetTickCount64() API returned value


WasError: boolean;

Set to TRUE if this calls failed
- i.e. if EInterfaceFactory was raised for TInterfaceStub, or if TInterfaceMock did notify its associated TSynTestCase via a Check()
- CustomResults/Results will contain the error message


function Results: RawUtf8;

The result returned after execution
- this method will return Method^.DefaultResult if CustomResults=''


procedure AddAsText(WR: TJsonWriter; aScope: TInterfaceStubLogLayouts; SepChar: AnsiChar = ',');

Append the log in textual format
- typical output is as such:

 Add(10,20)=[30],

or, if WasError is TRUE:

 Divide(20,0) error "divide by zero",

1.3.23. TInterfaceStub

TInterfaceStub = class(TInterfaceResolver)

Used to stub an interface implementation
- define the expected workflow in a fluent interface using Executes / Fails / Returns / Raises
- this class will be inherited by TInterfaceMock which will contain some additional methods dedicated to mocking behavior (e.g. including in tests)
- each instance of this class will be owned by its generated fake implementation class (retrieved at constructor out parameter): when the stubed/mocked interface is freed, its associated TInterfaceStub will be freed - so you do not need to protect TInterfaceStub.Create with a try..finally clause, since it will be released when no more needed
- inherits from TInterfaceResolver so match TInjectableObject expectations


constructor Create(const aInterfaceName: RawUtf8; out aStubbedInterface); reintroduce; overload;

Initialize an interface stub from an interface name (e.g. 'IMyInterface')
- you shall have registered the interface by a previous call to TInterfaceFactory.Get(TypeInfo(IMyInterface)) or RegisterInterfaces([])
- if the supplied name has not been previously registered, raise an Exception


constructor Create(aInterface: PRttiInfo); reintroduce; overload;

Prepare an interface stub from TypeInfo(IMyInterface) for later injection
- create several TInterfaceStub instances for a given TInjectableObject

 procedure TMyTestCase.OneTestCaseMethod;
 var Test: IServiceToBeTested;
 begin
   Test := TServiceToBeTested.CreateInjected([],
     TInterfaceStub.Create(TypeInfo(ICalculator)),
     TInterfaceMock.Create(TypeInfo(IPersistence),self).
       ExpectsCount('SaveItem',qoEqualTo,1)]);

constructor Create(const aGuid: TGuid); reintroduce; overload;

Prepare an interface stub from a given TGuid for later injection
- you shall have registered the interface by a previous call to

 TInterfaceFactory.RegisterInterfaces([TypeInfo(IMyInterface),...])

- then create TInterfaceStub instances for a given TInjectableObject:

 procedure TMyTestCase.OneTestCaseMethod;
 var Test: IServiceToBeTested;
 begin
   Test := TServiceToBeTested.CreateInjected(
     [IMyInterface],
     TInterfaceMock.Create(IPersistence,self).
       ExpectsCount('SaveItem',qoEqualTo,1)]);

constructor Create(aFactory: TInterfaceFactory; const aInterfaceName: RawUtf8); reintroduce; overload; virtual;

Low-level internal constructor
- you should not call this method, but the overloaded alternatives


constructor Create(aInterface: PRttiInfo; out aStubbedInterface); reintroduce; overload;

Initialize an interface stub from TypeInfo(IMyInterface)
- assign the fake class instance to a stubbed interface variable:

var
  I: ICalculator;
 ...
  TInterfaceStub.Create(TypeInfo(ICalculator),I);
  Check(I.Add(10,20)=0,'Default result');

constructor Create(const aGuid: TGuid; out aStubbedInterface); reintroduce; overload;

Initialize an interface stub from an interface Guid
- you shall have registered the interface by a previous call to

 TInterfaceFactory.RegisterInterfaces([TypeInfo(IMyInterface),...])

- once registered, create and use the fake class instance as such:

var
  I: ICalculator;
 ...
  TInterfaceStub.Create(ICalculator,I);
  Check(I.Add(10,20)=0,'Default result');

- if the supplied TGuid has not been previously registered, raise an Exception


function Executes(const aMethodName: RawUtf8; const aParams: array of const; const aEvent: TOnInterfaceStubExecuteVariant; const aEventParams: RawUtf8 = ''): TInterfaceStub; overload;

Add an execution rule for a given method and a set of parameters, with Variant marshalling
- if execution context matches the supplied aParams value, aEvent is triggered
- optional aEventParams parameter will be transmitted to aEvent handler
- raise an Exception if the method name does not exist for this interface


function Executes(const aMethodName, aParams: RawUtf8; const aEvent: TOnInterfaceStubExecuteVariant; const aEventParams: RawUtf8 = ''): TInterfaceStub; overload;

Add an execution rule for a given method and a set of parameters, with Variant marshalling
- if execution context matches the supplied aParams value, aEvent is triggered
- optional aEventParams parameter will be transmitted to aEvent handler
- raise an Exception if the method name does not exist for this interface


function Executes(aLog: TSynLogClass; aLogLevel: TSynLogLevel; aKind: TInterfaceMethodParamsDocVariantKind): TInterfaceStub; overload;

Will add execution rules for all methods to log the input parameters
- aKind will define how the input parameters are serialized in JSON


function Executes(const aEvent: TOnInterfaceStubExecuteVariant; const aEventParams: RawUtf8 = ''): TInterfaceStub; overload;

Add an execution rule for all methods, with Variant marshalling
- optional aEventParams parameter will be transmitted to aEvent handler
- callback's Ctxt: TOnInterfaceStubExecuteParamsVariant's Method field will identify the executed method


function Executes(const aMethodName, aParams: RawUtf8; const aEvent: TOnInterfaceStubExecuteJson; const aEventParams: RawUtf8 = ''): TInterfaceStub; overload;

Add an execution rule for a given method and a set of parameters, with JSON marshalling
- if execution context matches the supplied aParams value, aEvent is triggered
- optional aEventParams parameter will be transmitted to aEvent handler
- raise an Exception if the method name does not exist for this interface


function Executes(const aMethodName: RawUtf8; const aEvent: TOnInterfaceStubExecuteJson; const aEventParams: RawUtf8 = ''): TInterfaceStub; overload;

Add an execution rule for a given method, with JSON marshalling
- optional aEventParams parameter will be transmitted to aEvent handler
- raise an Exception if the method name does not exist for this interface


function Executes(const aMethodName: RawUtf8; const aEvent: TOnInterfaceStubExecuteVariant; const aEventParams: RawUtf8 = ''): TInterfaceStub; overload;

Add an execution rule for a given method, with Variant marshalling
- optional aEventParams parameter will be transmitted to aEvent handler
- raise an Exception if the method name does not exist for this interface


function Executes(const aMethodName: RawUtf8; const aParams: array of const; const aEvent: TOnInterfaceStubExecuteJson; const aEventParams: RawUtf8 = ''): TInterfaceStub; overload;

Add an execution rule for a given method and a set of parameters, with JSON marshalling
- if execution context matches the supplied aParams value, aEvent is triggered
- optional aEventParams parameter will be transmitted to aEvent handler
- raise an Exception if the method name does not exist for this interface


function ExpectsCount(const aMethodName: RawUtf8; const aParams: array of const; aOperator: TInterfaceStubRuleOperator; aValue: cardinal): TInterfaceStub; overload;

Add a pass count expectation rule for a given method and a set of parameters
- those rules will be evaluated at Destroy execution
- only qoEqualTo..qoGreaterThanOrEqualTo are relevant here
- it will raise EInterfaceFactory for TInterfaceStub, but TInterfaceMock will push the failure to the associated test case
- raise an Exception if the method name does not exist for this interface


function ExpectsCount(const aMethodName, aParams: RawUtf8; aOperator: TInterfaceStubRuleOperator; aValue: cardinal): TInterfaceStub; overload;

Add a pass count expectation rule for a given method and a set of parameters
- those rules will be evaluated at Destroy execution
- only qoEqualTo..qoGreaterThanOrEqualTo are relevant here
- it will raise EInterfaceFactory for TInterfaceStub, but TInterfaceMock will push the failure to the associated test case
- raise an Exception if the method name does not exist for this interface


function ExpectsCount(const aMethodName: RawUtf8; aOperator: TInterfaceStubRuleOperator; aValue: cardinal): TInterfaceStub; overload;

Add a pass count expectation rule for a given method
- those rules will be evaluated at Destroy execution
- only qoEqualTo..qoGreaterThanOrEqualTo are relevant here
- it will raise EInterfaceFactory for TInterfaceStub, but TInterfaceMock will push the failure to the associated test case
- raise an Exception if the method name does not exist for this interface


function ExpectsTrace(const aMethodName, aParams: RawUtf8; aValue: cardinal): TInterfaceStub; overload;

Add a hash-based execution expectation rule for a given method and a set of parameters
- those rules will be evaluated at Destroy execution
- supplied aValue is a Hash32() of the trace in LogAsText format
- it will raise EInterfaceFactory for TInterfaceStub, but TInterfaceMock will push the failure to the associated test case
- raise an Exception if the method name does not exist for this interface


function ExpectsTrace(const aMethodName: RawUtf8; aValue: cardinal): TInterfaceStub; overload;

Add a hash-based execution expectation rule for a given method
- those rules will be evaluated at Destroy execution
- supplied aValue is a Hash32() of the trace in LogAsText format
- it will raise EInterfaceFactory for TInterfaceStub, but TInterfaceMock will push the failure to the associated test case
- raise an Exception if the method name does not exist for this interface


function ExpectsTrace(aValue: cardinal): TInterfaceStub; overload;

Add a hash-based execution expectation rule for the whole interface
- those rules will be evaluated at Destroy execution
- supplied aValue is a Hash32() of the trace in LogAsText format
- it will raise EInterfaceFactory for TInterfaceStub, but TInterfaceMock will push the failure to the associated test case


function ExpectsTrace(const aMethodName, aParams, aValue: RawUtf8): TInterfaceStub; overload;

Add a JSON-based execution expectation rule for a given method and a set of parameters
- those rules will be evaluated at Destroy execution
- supplied aValue is the trace in LogAsText format
- it will raise EInterfaceFactory for TInterfaceStub, but TInterfaceMock will push the failure to the associated test case
- raise an Exception if the method name does not exist for this interface


function ExpectsTrace(const aMethodName, aValue: RawUtf8): TInterfaceStub; overload;

Add a JSON-based execution expectation rule for a given method
- those rules will be evaluated at Destroy execution
- supplied aValue is the trace in LogAsText format
- it will raise EInterfaceFactory for TInterfaceStub, but TInterfaceMock will push the failure to the associated test case
- raise an Exception if the method name does not exist for this interface


function ExpectsTrace(const aMethodName: RawUtf8; const aParams: array of const; aValue: cardinal): TInterfaceStub; overload;

Add a hash-based execution expectation rule for a given method and a set of parameters
- those rules will be evaluated at Destroy execution
- supplied aValue is a Hash32() of the trace in LogAsText format
- it will raise EInterfaceFactory for TInterfaceStub, but TInterfaceMock will push the failure to the associated test case
- raise an Exception if the method name does not exist for this interface


function ExpectsTrace(const aValue: RawUtf8): TInterfaceStub; overload;

Add a JSON-based execution expectation rule for the whole interface
- those rules will be evaluated at Destroy execution
- supplied aValue is the trace in LogAsText format
- it will raise EInterfaceFactory for TInterfaceStub, but TInterfaceMock will push the failure to the associated test case


function ExpectsTrace(const aMethodName: RawUtf8; const aParams: array of const; const aValue: RawUtf8): TInterfaceStub; overload;

Add a JSON-based execution expectation rule for a given method and a set of parameters
- those rules will be evaluated at Destroy execution
- supplied aValue is the trace in LogAsText format
- it will raise EInterfaceFactory for TInterfaceStub, but TInterfaceMock will push the failure to the associated test case
- raise an Exception if the method name does not exist for this interface


function Fails(const aMethodName, aParams, aErrorMsg: RawUtf8): TInterfaceStub; overload;

Add an error rule for a given method and a set of parameters
- an error will be returned to the caller, with aErrorMsg as message
- it will raise EInterfaceFactory for TInterfaceStub, but TInterfaceMock will push the failure to the associated test case
- raise an Exception if the method name does not exist for this interface


function Fails(const aMethodName, aErrorMsg: RawUtf8): TInterfaceStub; overload;

Add an error rule for a given method
- an error will be returned to the caller, with aErrorMsg as message
- it will raise EInterfaceFactory for TInterfaceStub, but TInterfaceMock will push the failure to the associated test case
- raise an Exception if the method name does not exist for this interface


function Fails(const aMethodName: RawUtf8; const aParams: array of const; const aErrorMsg: RawUtf8): TInterfaceStub; overload;

Add an error rule for a given method and a set of parameters
- an error will be returned to the caller, with aErrorMsg as message
- it will raise EInterfaceFactory for TInterfaceStub, but TInterfaceMock will push the failure to the associated test case
- raise an Exception if the method name does not exist for this interface


function Implements(aInterface: PRttiInfo): boolean; override;

Check if can resolve the supplied interface RTTI


function LogAsText(SepChar: AnsiChar = ','): RawUtf8;

The stubbed method execution trace converted as text
- typical output is a list of calls separated by commas:

 Add(10,20)=[30],Divide(20,0) error "divide by zero"

function Raises(const aMethodName: RawUtf8; aException: ExceptClass; const aMessage: string): TInterfaceStub; overload;

Add an exception rule for a given method
- will create and raise the specified exception for this method
- raise an Exception if the method name does not exist for this interface


function Raises(const aMethodName, aParams: RawUtf8; aException: ExceptClass; const aMessage: string): TInterfaceStub; overload;

Add an exception rule for a given method and a set of parameters
- will create and raise the specified exception for this method, if the execution context matches the supplied aParams value
- raise an Exception if the method name does not exist for this interface


function Raises(const aMethodName: RawUtf8; const aParams: array of const; aException: ExceptClass; const aMessage: string): TInterfaceStub; overload;

Add an exception rule for a given method and a set of parameters
- will create and raise the specified exception for this method, if the execution context matches the supplied aParams value
- raise an Exception if the method name does not exist for this interface


function Returns(const aMethodName, aExpectedResults: RawUtf8): TInterfaceStub; overload;

Add an evaluation rule for a given method
- aExpectedResults JSON array will be returned to the caller
- raise an Exception if the method name does not exist for this interface


function Returns(const aMethodName: RawUtf8; const aExpectedResults: array of const): TInterfaceStub; overload;

Add an evaluation rule for a given method
- aExpectedResults will be returned to the caller after conversion to a JSON array
- raise an Exception if the method name does not exist for this interface


function Returns(const aMethodName: RawUtf8; const aParams, aExpectedResults: array of const): TInterfaceStub; overload;

Add an evaluation rule for a given method and a set of parameters
- aExpectedResults JSON array will be returned to the caller
- raise an Exception if the method name does not exist for this interface


function Returns(const aMethodName, aParams, aExpectedResults: RawUtf8): TInterfaceStub; overload;

Add an evaluation rule for a given method and a set of parameters
- aExpectedResults JSON array will be returned to the caller
- raise an Exception if the method name does not exist for this interface


function SetOptions(Options: TInterfaceStubOptions): TInterfaceStub;

Set the optional stubing/mocking options
- same as the Options property, but in a fluent-style interface


procedure ClearLog;

Reset the internal trace
- Log, LogAsText, LogHash and LogCount will be initialized


property InterfaceFactory: TInterfaceFactory read fInterface;

Access to the registered Interface RTTI information


property LastInterfacedObjectFake: TInterfacedObject read fLastInterfacedObjectFake;

Returns the last created TInterfacedObject instance
- e.g. corresponding to the out aStubbedInterface parameter of Create()


property Log: TInterfaceStubLogDynArray read fLogs;

The stubbed method execution trace items


property LogCount: integer read fLogCount;

The stubbed method execution trace number of items


property LogHash: cardinal read GetLogHash;

The stubbed method execution trace converted as one numerical hash
- returns Hash32(LogAsText)


property Options: TInterfaceStubOptions read fOptions write IntSetOptions;

Optional stubing/mocking options
- you can use the SetOptions() method in a fluent-style interface


1.3.24. TInterfaceMock

TInterfaceMock = class(TInterfaceStub)

Used to mock an interface implementation via expect-run-verify pattern
- TInterfaceStub will raise an exception on Fails(), ExpectsCount() or ExpectsTrace() rule activation, but TInterfaceMock will call TSynTestCase.Check() with no exception with such rules, as expected by a mocked interface
- this class will follow the expect-run-verify pattern, i.e. expectations are defined before running the test, and verification is performed when the instance is released - use TInterfaceMockSpy if you prefer the more explicit run-verify pattern


constructor Create(aInterface: PRttiInfo; aTestCase: TSynTestCase); reintroduce; overload;

Initialize an interface mock from TypeInfo(IMyInterface) for later injection
- aTestCase.Check() will be called in case of mocking failure


constructor Create(const aGuid: TGuid; aTestCase: TSynTestCase); reintroduce; overload;

Initialize an interface mock from TypeInfo(IMyInterface) for later injection
- aTestCase.Check() will be called in case of mocking failure


constructor Create(const aInterfaceName: RawUtf8; out aMockedInterface; aTestCase: TSynTestCase); reintroduce; overload;

Initialize an interface mock from an interface name (e.g. 'IMyInterface')
- aTestCase.Check() will be called in case of mocking failure
- you shall have registered the interface by a previous call to TInterfaceFactory.Get(TypeInfo(IMyInterface)) or RegisterInterfaces()
- if the supplied name has not been previously registered, raise an Exception


constructor Create(aInterface: PRttiInfo; out aMockedInterface; aTestCase: TSynTestCase); reintroduce; overload;

Initialize an interface mock from TypeInfo(IMyInterface)
- aTestCase.Check() will be called in case of mocking failure

 procedure TMyTestCase.OneTestCaseMethod;
 var Persist: IPersistence;
 ...
   TInterfaceMock.Create(TypeInfo(IPersistence),Persist,self).
     ExpectsCount('SaveItem',qoEqualTo,1)]);

constructor Create(const aGuid: TGuid; out aMockedInterface; aTestCase: TSynTestCase); reintroduce; overload;

Initialize an interface mock from an interface TGuid
- aTestCase.Check() will be called during validation of all Expects*()
- you shall have registered the interface by a previous call to

 TInterfaceFactory.RegisterInterfaces([TypeInfo(IPersistence),...])

- once registered, create and use the fake class instance as such:

procedure TMyTestCase.OneTestCaseMethod;
var
  Persist: IPersistence;
 ...
   TInterfaceMock.Create(IPersistence,Persist,self).
     ExpectsCount('SaveItem',qoEqualTo,1)]);

- if the supplied TGuid has not been previously registered, raise an Exception


property TestCase: TSynTestCase read fTestCase;

The associated test case


1.3.25. TInterfaceMockSpy

TInterfaceMockSpy = class(TInterfaceMock)

Used to mock an interface implementation via run-verify pattern
- this class will implement a so called "test-spy" mocking pattern, i.e. no expectation is to be declared at first, but all calls are internally logged (i.e. it force imoLogMethodCallsAndResults option to be defined), and can afterwards been check via Verify() calls


constructor Create(aFactory: TInterfaceFactory; const aInterfaceName: RawUtf8); override;

This will set and force imoLogMethodCallsAndResults option as needed
- you should not call this method, but the overloaded alternatives


procedure Verify(const aMethodName, aTrace: RawUtf8; aScope: TInterfaceMockSpyCheck); overload;

Check an execution trace for a specified method
- text trace format will follow specified scope, e.g.

 Verify('Add','(10,30),(2,35)',chkNameParams);

or include parameters and function results:

 Verify('Add','(10,30)=[300],(2,35)=[37]',chkNameParamsResults);

- if aMethodName does not exists or aScope=chkName, will raise an exception


procedure Verify(const aMethodName, aParams, aTrace: RawUtf8); overload;

Check an execution trace for a specified method and parameters
- text trace format shall contain only results, e.g.

 Verify('Add','2,35','[37]');

procedure Verify(const aMethodName: RawUtf8; const aParams: array of const; const aTrace: RawUtf8); overload;

Check an execution trace for a specified method and parameters
- text trace format shall contain only results, e.g.

 Verify('Add',[2,35],'[37]');

procedure Verify(const aTrace: RawUtf8; aScope: TInterfaceMockSpyCheck); overload;

Check an execution trace for the global interface
- text trace format shall follow method calls, e.g.

 Verify('Multiply,Add',chkName);

or may include parameters:

 Verify('Multiply(10,30),Add(2,35)',chkNameParams);

or include parameters and function results:

 Verify('Multiply(10,30)=[300],Add(2,35)=[37]',chkNameParamsResults);

procedure Verify(const aMethodName: RawUtf8; aOperator: TInterfaceStubRuleOperator = ioGreaterThan; aCount: cardinal = 0); overload;

Check that a method has been called a specify number of times


procedure Verify(const aMethodName, aParams: RawUtf8; aOperator: TInterfaceStubRuleOperator = ioGreaterThan; aCount: cardinal = 0); overload;

Check a method calls count with a set of parameters
- parameters shall be defined as a JSON array of values


procedure Verify(const aMethodName: RawUtf8; const aParams: array of const; aOperator: TInterfaceStubRuleOperator = ioGreaterThan; aCount: cardinal = 0); overload;

Check a method calls count with a set of parameters
- parameters shall be defined as a JSON array of values


1.3.26. TFakeCallStack

TFakeCallStack = packed record

Map the stack memory layout at TInterfacedObjectFake.FakeCall()


1.3.27. TFakeCallContext

TFakeCallContext = record

Raw execution context for TInterfacedObjectFakeRaw.FakeCall*() methods


ServiceCustomAnswerPoint: PServiceCustomAnswer;

Type of value stored into result


1.3.28. TInterfacedObjectFakeRaw

TInterfacedObjectFakeRaw = class(TInterfacedObject)

Abstract class handling a generic interface implementation class
- implements a simple cross-CPU JIT engine to redirect to FakeCall
- note: inheriting from TSynInterfacedObject is not feasible


constructor Create(aFactory: TInterfaceFactory); reintroduce;

Create an instance, using the specified interface


procedure Get(out Obj);

Retrieve one instance of this interface, increasing its RefCount


procedure GetNoAddRef(out Obj);

Retrieve one instance of this interface, without increasing its RefCount


property Factory: TInterfaceFactory read fFactory;

The associated interface factory class


1.3.29. TInterfacedObjectFake

TInterfacedObjectFake = class(TInterfacedObjectFakeRaw)

Instances of this class will emulate a given interface over JSON content
- as used e.g. by TInterfaceFactoryClient.CreateFakeInstance


constructor Create(aFactory: TInterfaceFactory; aServiceFactory: TObject; aOptions: TInterfacedObjectFakeOptions; const aInvoke: TOnFakeInstanceInvoke; const aNotifyDestroy: TOnFakeInstanceDestroy); reintroduce;

Create an instance, using the specified interface and factory


destructor Destroy; override;

Release the remote server instance (in sicClientDriven mode);


property FakeID: TInterfacedObjectFakeID read fFakeID;

How TInterfacedObjectFake identify this instance
- match the ID used in sicClientDriven mode of a service
- match the TInterfacedObjectFakeServer 32-bit identifier of a callback


1.3.30. TInterfacedObjectFakeCallback

TInterfacedObjectFakeCallback = class(TInterfacedObjectFake)

Abstract class defining a FakeInvoke() virtual method via a TOnFakeInstanceInvoke signature


1.3.31. TInterfaceMethodExecuteRaw

TInterfaceMethodExecuteRaw = class(TObject)

Abtract execution of a TInterfacedObject method


constructor Create(aFactory: TInterfaceFactory; aMethod: PInterfaceMethod; const aOptions: TInterfaceMethodOptions); virtual;

Initialize the execution instance


procedure AddInterceptor(const Hook: TOnInterfaceMethodExecute);

Allow to hook method execution
- if optInterceptInputOutput is defined in Options, then Sender.Input/Output fields will contain the execution data context when Hook is called


procedure AddInterceptors(const Hook: TInterfaceMethodExecuteEventDynArray);

Allow to hook method execution
- if optInterceptInputOutput is defined in Options, then Sender.Input/Output fields will contain the execution data context when Hook[] are called


property BackgroundExecutionThread: TSynBackgroundThreadMethod read fBackgroundExecutionThread write fBackgroundExecutionThread;

Reference to the background execution thread, if any


property CurrentStep: TInterfaceMethodExecuteEventStep read fCurrentStep write fCurrentStep;

The current state of the execution


property ExecutedInstancesFailed: TRawUtf8DynArray read fExecutedInstancesFailed;

Contains exception serialization after ExecuteJson of multiple instances
- follows the Instances[] order as supplied to RawExecute/ExecuteJson
- if only a single Instances[] is supplied, the exception will be propagated to the caller, unless optIgnoreException option is defined
- if more than one Instances[] is supplied, any raised Exception will be serialized using ObjectToJsonDebug(), or this property will be left to its default nil content if no exception occurred


property Factory: TInterfaceFactory read fFactory;

Low-level direct access to the associated interface factory information


property Input: TDocVariantData read fInput;

Set if optInterceptInputOutput is defined in TServiceFactoryServer.Options
- contains a dvObject with input parameters as "argname":value pairs
- this is a read-only property: you cannot change the input content


property LastException: Exception read fLastException;

Only set during AddInterceptor() callback execution, if Step is smsError


property Method: PInterfaceMethod read fMethod;

Low-level direct access to the associated method information


property OnExecute: TInterfaceMethodExecuteEventDynArray read fOnExecute;

Reference to the actual execution method callbacks


property Options: TInterfaceMethodOptions read fOptions write SetOptions;

Associated settings, as copied from TServiceFactoryServer.Options


property Output: TDocVariantData read fOutput;

Set if optInterceptInputOutput is defined in TServiceFactoryServer.Options
- contains a dvObject with output parameters as "argname":value pairs
- this is a read-only property: you cannot change the output content


property Values: PPointerArray read fValues;

Low-level direct access to the current input/output parameter values
- you should not need to access this, but rather set optInterceptInputOutput in Options, and read Input/Output content


1.3.32. TInterfaceMethodExecute

TInterfaceMethodExecute = class(TInterfaceMethodExecuteRaw)

Execute a method of a TInterfacedObject instance, from/to JSON


destructor Destroy; override;

Finalize the execution instance


function ExecuteJson(const Instances: array of pointer; P: PUtf8Char; Res: TJsonWriter; Error: PShortString = nil; ResAsJsonObject: boolean = false): boolean;

Execute the corresponding method of weak IInvokable references
- will retrieve a JSON array of parameters from P buffer (as [1,"par2",3])
- will append a JSON array of results in Res, or set an Error message, or a JSON object (with parameter names) in Res if ResultAsJsonObject is set
- if one Instances[] is supplied, any exception will be propagated (unless optIgnoreException is set); if more than one Instances[] is supplied, corresponding ExecutedInstancesFailed[] property will be filled with the JSON serialized exception


function ExecuteJsonCallback(Instance: pointer; const params: RawUtf8; output: PRawUtf8): boolean;

Execute the corresponding method of one weak IInvokable reference
- exepect no output argument, i.e. no returned data, unless output is set
- this version will identify TInterfacedObjectFake implementations, and will call directly fInvoke() if possible, to avoid JSON marshalling
- expect params value to be without [ ], just like TOnFakeInstanceInvoke


function ExecuteJsonFake(Instance: pointer; params: PUtf8Char): boolean;

Execute directly TInterfacedObjectFake.fInvoke()
- expect params value to be with [ ], just like ExecuteJson


function TempTextWriter: TJsonWriter;

Allow to use an instance-specific temporary TOrmWriter


property OnCallback: TOnInterfaceMethodExecuteCallback read fOnCallback write fOnCallback;

Points e.g. to TRestServerUriContext.ExecuteCallback which redirects to TServiceContainerServer.GetFakeCallback


property ServiceCustomAnswerHead: RawUtf8 read fServiceCustomAnswerHead write fServiceCustomAnswerHead;

Set from output TServiceCustomAnswer.Header result parameter


property ServiceCustomAnswerStatus: cardinal read fServiceCustomAnswerStatus write fServiceCustomAnswerStatus;

Set from output TServiceCustomAnswer.Status or TServiceCustomStatus result parameter


1.3.33. TInterfaceMethodExecuteCached

TInterfaceMethodExecuteCached = class(TInterfaceMethodExecute)

Reusable interface method execution from/to JSON
- used e.g. by TServiceFactoryServer.ExecuteJson or TMvcRendererAbstract.ExecuteCommand


constructor Create(aFactory: TInterfaceFactory; aMethod: PInterfaceMethod; const aOptions: TInterfaceMethodOptions); override;

Initialize the execution instance


destructor Destroy; override;

Finalize this execution context


procedure Acquire(opt: TInterfaceMethodOptions; out exec: TInterfaceMethodExecuteCached; out WR: TJsonWriter);

Will use this instance if possible, or create a temporary one


class procedure Prepare(aFactory: TInterfaceFactory; out Cached: TInterfaceMethodExecuteCachedDynArray);

Initialize a TInterfaceMethodExecuteCachedDynArray of per-method caches


procedure Release(exec: TInterfaceMethodExecuteCached);

Will release this instance if was acquired, or free a temporary one


1.4. Types implemented in the mormot.core.interfaces unit

1.4.1. PInterfaceMethod

PInterfaceMethod = ^TInterfaceMethod;

A pointer to an interface-based service provider method description
- since TInterfaceFactory instances are shared in a global list, we can safely use such pointers in our code to refer to a particular method


1.4.2. PInterfaceMethodArgument

PInterfaceMethodArgument = ^TInterfaceMethodArgument;

Pointer to a service provider method argument


1.4.3. TInjectableObjectClass

TInjectableObjectClass = class of TInjectableObject;

Class-reference type (metaclass) of a TInjectableObject type


1.4.4. TInterfacedObjectFakeID

TInterfacedObjectFakeID = type cardinal;

How TInterfacedObjectFake identify each instance
- match the ID used in sicClientDriven mode of a service
- match the TInterfacedObjectFakeServer 32-bit identifier of a callback


1.4.5. TInterfacedObjectFakeOption

TInterfacedObjectFakeOption = ( ifoJsonAsExtended, ifoDontStoreVoidJson );

How TInterfacedObjectFake will perform its execution
- by default, fInvoke() will receive standard JSON content, unless ifoJsonAsExtended is set, and extended JSON is used
- ifoDontStoreVoidJson will ensure objects and records won't include default void fields in JSON serialization


1.4.6. TInterfacedObjectFakeOptions

TInterfacedObjectFakeOptions = set of TInterfacedObjectFakeOption;

Defines how TInterfacedObjectFakeRaw will perform its execution


1.4.7. TInterfacedObjectObjArray

TInterfacedObjectObjArray = array of TInterfacedObject;

Used to store a list of TInterfacedObject instances


1.4.8. TInterfaceFactoryArgumentDynArray

TInterfaceFactoryArgumentDynArray = array of TInterfaceFactoryArgument;

Index-based reference to several TInterfaceFactory argument


1.4.9. TInterfaceFactoryMethodBits

TInterfaceFactoryMethodBits = set of 0 .. MAX_METHOD_COUNT - 1;

May be used to store the Methods[] indexes of a TInterfaceFactory
- current implementation handles up to 128 methods, a limit above which "Interface Segregation" principle is obviously broken


1.4.10. TInterfaceFactoryObjArray

TInterfaceFactoryObjArray = array of TInterfaceFactory;

A dynamic array of TInterfaceFactory instances


1.4.11. TInterfaceFactoryPerArgumentDynArray

TInterfaceFactoryPerArgumentDynArray = array[TInterfaceMethodValueType] of TInterfaceFactoryArgumentDynArray;

Per-type reference of TInterfaceFactory arguments


1.4.12. TInterfaceMethodArgumentDynArray

TInterfaceMethodArgumentDynArray = array of TInterfaceMethodArgument;

Describe a service provider method arguments


1.4.13. TInterfaceMethodDynArray

TInterfaceMethodDynArray = array of TInterfaceMethod;

Describe all mtehods of an interface-based service provider


1.4.14. TInterfaceMethodExecuteCachedDynArray

TInterfaceMethodExecuteCachedDynArray = array of TInterfaceMethodExecuteCached;

Set reusable interface methods execution from/to JSON


1.4.15. TInterfaceMethodExecuteEventDynArray

TInterfaceMethodExecuteEventDynArray = array of TOnInterfaceMethodExecute;

Store one or several TInterfaceMethodExecute.OnExecute signatures


1.4.16. TInterfaceMethodExecuteEventStep

TInterfaceMethodExecuteEventStep = ( smsUndefined, smsBefore, smsAfter, smsError );

The current step of a TInterfaceMethodExecute.OnExecute call


1.4.17. TInterfaceMethodOption

TInterfaceMethodOption = ( optExecGlobalLocked, optFreeGlobalLocked, optExecLockedPerInterface, optFreeLockedPerInterface, optExecInPerInterfaceThread, optFreeInPerInterfaceThread, optFreeDelayed, optExecInMainThread, optFreeInMainThread, optVariantCopiedByReference, optVariantFloatAllowed, optInterceptInputOutput, optNoLogInput, optNoLogOutput, optErrorOnMissingParam, optForceStandardJson, optDontStoreVoidJson, optIgnoreException, optFreeTimeout );

Possible service provider method options, e.g. about logging or execution
- see TInterfaceMethodOptions for a description of each available option


1.4.18. TInterfaceMethodOptions

TInterfaceMethodOptions = set of TInterfaceMethodOption;

Set of per-method execution options for an interface-based service provider
- by default, method executions are concurrent, for better server responsiveness; if you set optExecLockedPerInterface/optFreeLockedPerInterface, all methods of a given interface will be executed within a critical section; if you set optExecGlobalLocked/optFreeGlobalLocked, execution is done within a critical section global to all interfaces
- optExecInMainThread will force the method to be called within a RunningThread.Synchronize() call - it can be used e.g. if your implementation rely heavily on COM servers - by default, service methods are called within the thread which received them, on multi-thread server instances (e.g. TSqlite3HttpServer or TRestServerNamedPipeResponse), for better response time and CPU use (this is the technical reason why service implementation methods have to handle multi-threading safety carefully, e.g. by using TOSLock mutex on purpose) - warning: a Windows Service has no 'main thread' concept, so should not use it
- optFreeInMainThread will force the _Release/Destroy method to be run in the main thread: setting this option for any method will affect the whole service class - is not set by default, for performance reasons
- optExecInPerInterfaceThread and optFreeInPerInterfaceThread will allow creation of a per-interface dedicated thread
- by default _Release is done within the service lock, unless optFreeDelayed is set and instances are released later (e.g. if may take some time)
- optVariantCopiedByReference and optVariantFloatAllowed are used to generate the proper TDocVariantData options
- if optInterceptInputOutput is set, TServiceFactoryServer.AddInterceptor() events will have their Sender.Input/Output values defined
- if optNoLogInput/optNoLogOutput is set, TSynLog and SetServiceLog database won't log any parameter values at input/output - this may be useful for regulatory/safety purposes, e.g. to ensure that no sensitive information (like a credit card number or a password), is logged during process - consider using TInterfaceFactory.RegisterUnsafeSpiType() instead if you prefer a more tuned filtering, for specific high-level types
- when parameters are transmitted as JSON object, any missing parameter will be replaced by their default value, unless optErrorOnMissingParam is defined to reject the call
- by default, it wil check for the client user agent, and use extended JSON if none is found (e.g. from WebSockets), or if it contains 'mORMot': you can set optForceStandardJson to ensure standard JSON is always returned
- optDontStoreVoidJson will reduce the JSON object verbosity by not writing void (e.g. 0 or '') properties when serializing objects and records
- any exceptions will be propagated during execution, unless optIgnoreException is set and the exception is trapped (not to be used unless you know what you are doing)
- optFreeTimeout will enable the time check of the _Release call using TRestServer.ServiceReleaseTimeoutMicrosec delay


1.4.19. TInterfaceMethodParamsDocVariantKind

TInterfaceMethodParamsDocVariantKind = ( pdvArray, pdvObject, pdvObjectFixed );

How TInterfaceMethod.TInterfaceMethod method will return the generated document
- will return either a dvObject or dvArray TDocVariantData, depending on the expected returned document layout
- returned content could be "normalized" (for any set or enumerate) if Kind is pdvObjectFixed


1.4.20. TInterfaceMethodValueAsm

TInterfaceMethodValueAsm = set of ( vPassedByReference, vIsQword, vIsDynArrayString, vIsInterfaceJson);

Set of low-level processing options at assembly level
- vPassedByReference is included if the parameter is passed as reference (i.e. defined as var/out, or is a record or a reference-counted type result)
- vIsQword is set for ValueType=imvInt64 over a QWord unsigned 64-bit value
- vIsDynArrayString is set for ValueType=imvDynArray of string values
- vIsInterfaceJson is set for an interface with custom JSON serializers


1.4.21. TInterfaceMethodValueDirection

TInterfaceMethodValueDirection = ( imdConst, imdVar, imdOut, imdResult );

Handled kind of parameters direction for an interface-based service method
- IN, IN/OUT, OUT directions can be applied to arguments, and will be available through our JSON-serialized remote access: smdVar and smdOut kind of parameters will be returned within the "result": JSON array
- smdResult is used for a function method, to handle the returned value


1.4.22. TInterfaceMethodValueDirections

TInterfaceMethodValueDirections = set of TInterfaceMethodValueDirection;

Set of parameters direction for an interface-based service method


1.4.23. TInterfaceMethodValueType

TInterfaceMethodValueType = ( imvNone, imvSelf, imvBoolean, imvEnum, imvSet, imvInteger, imvCardinal, imvInt64, imvDouble, imvDateTime, imvCurrency, imvRawUtf8, imvString, imvRawByteString, imvWideString, imvRecord, imvVariant, imvObject, imvRawJson, imvDynArray, imvInterface );

Handled kind of parameters for an interface-based service provider method
- we do not handle all kind of variables, but provide some enhanced types handled by JsonToObject/ObjectToJson functions (smvObject) or TDynArray.LoadFromJson / TJsonWriter.AddDynArrayJson methods (smvDynArray)
- records will be serialized as Base64 string, with our RecordSave/RecordLoad low-level format by default, or as true JSON objects since Delphi 2010 or after a Rtti.RegisterFromText/TRttiJson.RegisterCustomSerializer call
- imvRawJson will transmit the raw JSON content, without serialization


1.4.24. TInterfaceMethodValueTypes

TInterfaceMethodValueTypes = set of TInterfaceMethodValueType;

Set of parameters for an interface-based service provider method


1.4.25. TInterfaceMethodValueVar

TInterfaceMethodValueVar = ( imvvNone, imvvSelf, imvv64, imvvRawUtf8, imvvString, imvvWideString, imvvRecord, imvvObject, imvvDynArray, imvvInterface );

Handled kind of parameters internal variables for an interface-based method
- reference-counted variables will have their own storage
- all non referenced-counted variables are stored within some 64-bit content
- imvVariant kind of parameter will be handled as a special imvvRecord


1.4.26. TInterfaceMockSpyCheck

TInterfaceMockSpyCheck = ( chkName, chkNameParams, chkNameParamsResults );

How TInterfaceMockSpy.Verify() shall generate the calls trace


1.4.27. TInterfaceOption

TInterfaceOption = ( optByPassAuthentication, optResultAsJsonObject, optResultAsJsonObjectWithoutResult, optResultAsXMLObject, optResultAsXMLObjectIfAcceptOnlyXML, optExcludeServiceLogCustomAnswer );

Available execution options for an interface-based service provider
- mimics TServiceFactoryServer homonymous boolean properties


1.4.28. TInterfaceOptions

TInterfaceOptions = set of TInterfaceOption;

Set of execution options for an interface-based service provider
- mimics TServiceFactoryServer homonymous boolean properties
- as used by TServiceFactoryServerAbstract.SetWholeOptions()


1.4.29. TInterfaceResolverListEntries

TInterfaceResolverListEntries = array of TInterfaceResolverListEntry;

How TInterfaceResolverList store one interface/class


1.4.30. TInterfaceResolverObjArray

TInterfaceResolverObjArray = array of TInterfaceResolver;

Used to store a list of TInterfaceResolver instances


1.4.31. TInterfaceStubLogDynArray

TInterfaceStubLogDynArray = array of TInterfaceStubLog;

Used to keep track of all stubbed methods calls


1.4.32. TInterfaceStubLogLayout

TInterfaceStubLogLayout = ( wName, wParams, wResults );

Every potential part of TInterfaceStubLog.AddAsText() log entry


1.4.33. TInterfaceStubLogLayouts

TInterfaceStubLogLayouts = set of TInterfaceStubLogLayout;

Set the output layout of TInterfaceStubLog.AddAsText() log entry


1.4.34. TInterfaceStubOption

TInterfaceStubOption = ( imoLogMethodCallsAndResults, imoFakeInstanceWontReleaseTInterfaceStub, imoRaiseExceptionIfNoRuleDefined, imoReturnErrorIfNoRuleDefined, imoMockFailsWillPassTestCase );

Diverse options available to TInterfaceStub
- by default, method execution stack is not recorded - include imoLogMethodCallsAndResults in the options to track all method calls and the returned values; note that ExpectsTrace() method will set it
- by default, TInterfaceStub will be released when the stubed/mocked interface is released - include imoFakeInstanceWontReleaseTInterfaceStub in the options to force manual memory handling of TInterfaceStubs
- by default, all interfaces will return some default values, unless imoRaiseExceptionIfNoRuleDefined or imoReturnErrorIfNoRuleDefined is included in the options
- by default, any TInterfaceMock.Fails() rule execution will notify the TSynTestCase, unless imoMockFailsWillPassTestCase which will let test pass


1.4.35. TInterfaceStubOptions

TInterfaceStubOptions = set of TInterfaceStubOption;

Set of options available to TInterfaceStub


1.4.36. TInterfaceStubRuleKind

TInterfaceStubRuleKind = ( isUndefined, isExecutesJson, isExecutesVariant, isRaises, isReturns, isFails );

Diverse types of stubbing / mocking rules
- isUndefined is the first, since it will be a ExpectsCount() weak rule which may be overwritten by the other real run-time rules


1.4.37. TInterfaceStubRuleOperator

TInterfaceStubRuleOperator = ( ioUndefined, ioEqualTo, ioNotEqualTo, ioLessThan, ioLessThanOrEqualTo, ioGreaterThan, ioGreaterThanOrEqualTo, ioTraceMatch );

Supported comparison operators for stubbing / mocking rules


1.4.38. TOnFakeInstanceDestroy

TOnFakeInstanceDestroy = procedure(aFakeID: TInterfacedObjectFakeID) of object;

Event called when destroying a TInterfaceFactory's fake instance
- this method will be run when the fake class instance is destroyed (e.g. if aInstanceCreation is sicClientDriven, to notify the server than the client life time just finished)


1.4.39. TOnFakeInstanceInvoke

TOnFakeInstanceInvoke = function(const aMethod: TInterfaceMethod; const aParams: RawUtf8; aResult, aErrorMsg: PRawUtf8; aFakeID: PInterfacedObjectFakeID; aServiceCustomAnswer: PServiceCustomAnswer): boolean of object;

Event used by TInterfaceFactory and TInterfacedObjectFake to run a method from a fake instance using JSON marshaling for the parameters
- aMethod will specify which method is to be executed
- aParams will contain the input parameters, encoded as a JSON array, without the [ ] characters (e.g. '1,"arg2",3')
- shall return TRUE on success, or FALSE in case of failure, with a corresponding explanation in aErrorMsg
- method results shall be serialized as JSON in aResult; if aServiceCustomAnswer is not nil, the result shall use this record to set HTTP custom content and headers, and ignore aResult content
- aClientDrivenID can be set optionally to specify e.g. an URI-level session


1.4.40. TOnInterfaceMethodExecute

TOnInterfaceMethodExecute = procedure(Sender: TInterfaceMethodExecuteRaw; Step: TInterfaceMethodExecuteEventStep) of object;

The TInterfaceMethodExecute.OnExecute signature
- optInterceptInputOutput should be defined in Options so that Sender.Input/Output values will be filled with parameters (slower but easier to consume than Sender.Values raw pointers)
- is called for each Step, i.e. smsBefore/smsAfter
- smsError is called when TInterfaceMethodExecute.LastException was raised


1.4.41. TOnInterfaceMethodExecuteCallback

TOnInterfaceMethodExecuteCallback = procedure(var Ctxt: TJsonParserContext; ParamInterfaceInfo: TRttiJson; out Obj) of object;

Callback called by TInterfaceMethodExecute to process an interface callback parameter
- implementation should set the Obj local variable to an instance of a fake class implementing the aParamInfo interface


1.4.42. TOnInterfaceStubExecuteJson

TOnInterfaceStubExecuteJson = procedure( Ctxt: TOnInterfaceStubExecuteParamsJson) of object;

Event called by the TInterfaceStub.Executes() fluent method for JSON process
- by default Ctxt.result shall contain the default JSON array result for this method - use Ctxt.Named[] default properties, e.g. as

  P := pointer(Ctxt.Params);
  Ctxt.Returns([GetNextItemDouble(P)-GetNextItemDouble(P)]);

- you can call Ctxt.Error() to notify the caller for an execution error


1.4.43. TOnInterfaceStubExecuteVariant

TOnInterfaceStubExecuteVariant = procedure( Ctxt: TOnInterfaceStubExecuteParamsVariant) of object;

Event called by the TInterfaceStub.Executes() fluent method for variant process
- by default Ctxt.result shall contain the default JSON array result for this method - use Ctxt.Named[] default properties, e.g. as

 Ctxt['result'] := Ctxt['n1']-Ctxt['n2'];

or with Input[] / Output[] properties:

 with Ctxt do Output[0] := Input[0]-Input[1];

- you can call Ctxt.Error() to notify the caller for an execution error


1.4.44. TOnResolverCreateInstance

TOnResolverCreateInstance = procedure( Sender: TInterfaceResolver; Instance: TInterfacedObject) of object;

Event signature used by TInterfaceResolverList.OnCreateInstance


1.4.45. TOnServiceMethodExecuteCallback

TOnServiceMethodExecuteCallback = procedure(var Par: PUtf8Char; ParamInterfaceInfo: TRttiCustom; out Obj) of object;

Callback called by TInterfaceMethodExecute to process an interface callback parameter
- implementation should set the Obj local variable to an instance of a fake class implementing the aParamInfo interface


1.4.46. TServiceCustomStatus

TServiceCustomStatus = type cardinal;

An integer type to be used as result for a function method to customize the HTTP response code for interface-based services
- by default, our protocol returns HTTP_SUCCESS = 200 for any process
- using this type as result allow to return the execution error code as a regular HTTP_* response code, in addition to the regular JSON answer - i.e. there will be a "result" member in the transmitted JSON anyway
- the returned value should be in HTTP response code range, i.e. 200..599
- by design, HTTP_NOCONTENT can/should not be used: return HTTP_SUCCESS and set rsoHttp200WithNoBodyReturns204 option to let TRestServer.Uri decide and return HTTP_SUCCESS if there is an output body, or HTTP_NOCONTENT if void


1.4.47. TServiceInternalMethod

TServiceInternalMethod = ( imFree, imContract, imSignature, imInstance );

Internal pseudo methods when an interface is used as remote service
- match TInterfaceFactory MethodIndex 0..3
- imFree expects an associated ClientID, other methods won't


1.4.48. TServiceMethodValueType

TServiceMethodValueType = TInterfaceMethodValueType;

Backward compatibility types redirections


1.5. Constants implemented in the mormot.core.interfaces unit

1.5.1. ARGS_IN_STACK_SIZE

ARGS_IN_STACK_SIZE: array[TInterfaceMethodValueType] of cardinal = ( 0, POINTERBYTES, POINTERBYTES, POINTERBYTES, POINTERBYTES, POINTERBYTES, POINTERBYTES, 8, 8, 8, 8, POINTERBYTES, POINTERBYTES, POINTERBYTES, POINTERBYTES, POINTERBYTES, POINTERBYTES, POINTERBYTES, POINTERBYTES, POINTERBYTES, POINTERBYTES);

ImvNone imvSelf imvBoolean imvEnum imvSet imvInteger imvCardinal imvInt64 imvDouble imvDateTime imvCurrency imvRawUtf8 imvString imvRawByteString imvWideString imvRecord imvVariant imvObject imvRawJson imvDynArray imvInterface parameters are always aligned to 8 bytes boundaries on 64-bit ABI but may be on 32-bit or 64-bit on 32-bit CPU


1.5.2. ARGS_RESULT_BY_REF

ARGS_RESULT_BY_REF: TInterfaceMethodValueTypes = [imvRawUtf8, imvRawJson, imvString, imvRawByteString, imvWideString, imvRecord, imvVariant, imvDynArray];

ImvNone imvSelf imvBoolean imvEnum imvSet imvInteger imvCardinal imvInt64 imvDouble imvDateTime imvCurrency imvRawUtf8 imvString imvRawByteString imvWideString imvRecord imvVariant imvObject imvRawJson imvDynArray imvInterface


1.5.3. ARGS_TO_VAR

ARGS_TO_VAR: array[TInterfaceMethodValueType] of TInterfaceMethodValueVar = ( imvvNone, imvvSelf, imvv64, imvv64, imvv64, imvv64, imvv64, imvv64, imvv64, imvv64, imvv64, imvvRawUtf8, imvvString, imvvRawUtf8, imvvWideString, imvvRecord, imvvRecord, imvvObject, imvvRawUtf8, imvvDynArray, imvvInterface);

Ordinal values are stored within 64-bit buffer, and records in a RawUtf8


1.5.4. INTERFACEMETHOD_PERTHREADOPTIONS

INTERFACEMETHOD_PERTHREADOPTIONS: array[0..3] of TInterfaceMethodOptions = ( [optExecGlobalLocked, optFreeGlobalLocked], [optExecLockedPerInterface, optFreeLockedPerInterface], [optExecInPerInterfaceThread, optFreeInPerInterfaceThread], [optExecInMainThread, optFreeInMainThread]);

The related TInterfaceMethodOptions, grouped per thread mode


1.5.5. INTERFACEMETHOD_THREADOPTIONS

INTERFACEMETHOD_THREADOPTIONS = [ optExecGlobalLocked, optFreeGlobalLocked, optExecLockedPerInterface, optFreeLockedPerInterface, optExecInPerInterfaceThread, optFreeInPerInterfaceThread, optExecInMainThread, optFreeInMainThread];

The TInterfaceMethodOptions which are related to custom thread execution


1.5.6. JSON_BIN_MAGIC_C

JSON_BIN_MAGIC_C = $00b2bfef;

Marker used internally to pass ServiceMethod^.ArgsInputIsOctetStream
- used by both TRestServerRoutingRest.ExecuteSoaByInterface and TInterfaceMethodExecute.ExecuteJson, followed by a RawByteString pointer
- is a UTF-8 marker, ending with a #0 so to be identified within JSON


1.5.7. MAX_EXECSTACK

MAX_EXECSTACK = 1024;

1.5.8. MAX_METHOD_ARGS

MAX_METHOD_ARGS = 32;

Maximum number of method arguments handled by interfaces
- if you consider this as a low value, you should better define some records/classes as DTOs instead of multiplicating parameters: so don't ask to increase this value, we rather encourage writing clean code
- used e.g. to avoid creating dynamic arrays if not needed, and ease method calls


1.5.9. MAX_METHOD_COUNT

MAX_METHOD_COUNT = 128;

Maximum number of methods handled by interfaces
- if you think this constant is too low, you are about to break the "Interface Segregation" SOLID principle: so don't ask to increase this value, we won't allow to write obviously un-SOLID code! :)


1.5.10. REGEAX

REGEAX = 1;

32-bit integer param registers (in "register" calling convention)


1.5.11. RESERVED_VTABLE_SLOTS

RESERVED_VTABLE_SLOTS = 3;

IInterface QueryInterface, _AddRef and _Release methods are hard-coded


1.5.12. SERVICE_PSEUDO_METHOD

SERVICE_PSEUDO_METHOD: array[TServiceInternalMethod] of RawUtf8 = ( '_free_', '_contract_', '_signature_', '_instance_');

URI of some pseudo methods when an interface is used as remote service
- match TInterfaceFactory MethodIndex 0..3


1.5.13. SERVICE_PSEUDO_METHOD_COUNT

SERVICE_PSEUDO_METHOD_COUNT = length(SERVICE_PSEUDO_METHOD);

The number of MethodIndex which are a TServiceInternalMethod, i.e. 4


1.5.14. smdConst

smdConst = imdConst;

TServiceMethodValueDirection = TInterfaceMethodValueDirection items


1.5.15. smvNone

smvNone = imvNone;

TServiceMethodValueType = TInterfaceMethodValueType items


1.5.16. smvRecord

smvRecord = imvRecord;

SmvBinary = imvBinary; not defined any more (handle by RTTI itself)


1.5.17. smvvNone

smvvNone = imvvNone;

TServiceMethodValueVar = TInterfaceMethodValueVar items


1.5.18. VMTSTUBSIZE

VMTSTUBSIZE = 24 ;

Floating-point params are passed by reference


1.6. Functions or procedures implemented in the mormot.core.interfaces unit

Functions or proceduresDescription
BackgroundExecuteInstanceReleaseLow-level execution of TInterfacedObject._Release in a given background thread
BackgroundExecuteThreadMethodLow-level execution of a procedure of object in a given background thread
ObjectFromInterfaceLow-level function to retrieve the class instance implementing a given interface
ObjectFromInterfaceImplementsLow-level function to check if a class instance, retrieved from its interface variable, does in fact implement a given interface
PerThreadRunningContextAddressLow-level internal function returning the TServiceRunningContext threadvar
SetWeakAssign a Weak interface reference, to be used for circular references
SetWeakZeroRaise Internal Error C2170 on some Delphis assign a Weak interface reference, which will be ZEROed (set to nil) when the associated aObject and/or aValue will be released
ToTextReturns the interface name of a registered Guid, or its hexadecimal value
ToTextReturn the interface execution options set as text

1.6.1. BackgroundExecuteInstanceRelease

procedure BackgroundExecuteInstanceRelease(instance: TObject; backgroundThread: TSynBackgroundThreadMethod);

Low-level execution of TInterfacedObject._Release in a given background thread


1.6.2. BackgroundExecuteThreadMethod

procedure BackgroundExecuteThreadMethod(const method: TThreadMethod; backgroundThread: TSynBackgroundThreadMethod);

Low-level execution of a procedure of object in a given background thread


1.6.3. ObjectFromInterface

function ObjectFromInterface(const aValue: IInterface): TObject;

Low-level function to retrieve the class instance implementing a given interface
- this will work with interfaces stubs generated by the compiler, but also with TInterfaceFactory.CreateFakeInstance kind of classes
- returns nil if aValue is nil or not recognized


1.6.4. ObjectFromInterfaceImplements

function ObjectFromInterfaceImplements(const aValue: IInterface; const aInterface: TGuid): boolean;

Low-level function to check if a class instance, retrieved from its interface variable, does in fact implement a given interface
- this will call ObjectFromInterface(), so will work with interfaces stubs generated by the compiler, but also with TInterfaceFactory.CreateFakeInstance kind of classes


1.6.5. PerThreadRunningContextAddress

function PerThreadRunningContextAddress: pointer;

Low-level internal function returning the TServiceRunningContext threadvar
- mormot.rest.server.pas ServiceRunningContext function redirects to this
- not inlined to ensure the associated threadvar is always properly linked


1.6.6. SetWeak

procedure SetWeak(aInterfaceField: PInterface; const aValue: IInterface);

Assign a Weak interface reference, to be used for circular references
- by default setting aInterface.Field := aValue will increment the internal reference count of the implementation object: when underlying objects reference each other via interfaces (e.g. as parent and children), what causes the reference count to never reach zero, therefore resulting in memory leaks
- to avoid this issue, use this procedure instead


1.6.7. SetWeakZero

procedure SetWeakZero(aObject: TObject; aObjectInterfaceField: PInterface; const aValue: IInterface);

Raise Internal Error C2170 on some Delphis assign a Weak interface reference, which will be ZEROed (set to nil) when the associated aObject and/or aValue will be released
- this function is slower than SetWeak, but will avoid any GPF, by maintaining a list of per-instance weak interface field references, and hook the TObject.FreeInstance virtual method for proper zeroings
- thread-safe implementation, using per-class locked lists


1.6.8. ToText

function ToText(opt: TInterfaceMethodOptions): shortstring; overload;

Return the interface execution options set as text


1.6.9. ToText

function ToText(const aGuid: TGuid): ShortString; overload;

Returns the interface name of a registered Guid, or its hexadecimal value


1.7. Variables implemented in the mormot.core.interfaces unit

1.7.1. GlobalInterfaceResolver

GlobalInterfaceResolver: TInterfaceResolverList;

Global thread-safe list for process-wide interfaces resolution
- TInterfaceResolverInjected.RegisterGlobal/RegisterGlobalDelete class methods redirect to GlobalInterfaceResolver.Add/Delete
- initialization section of this unit will make at startup:

 GlobalInterfaceResolver.Add(TypeInfo(IAutoLocker), TAutoLocker);
 GlobalInterfaceResolver.Add(TypeInfo(ILockedDocVariant), TLockedDocVariant);

1.7.2. JSONPARSER_SERVICE

JSONPARSER_SERVICE: TJsonParserOptions = [jpoHandleCustomVariants, jpoIgnoreUnknownEnum, jpoIgnoreUnknownProperty, jpoIgnoreStringType, jpoAllowInt64Hex, jpoNullDontReleaseObjectInstance];

Default value for TInterfaceFactory.JsonParserOptions