Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Comment: | TServiceFactoryServerInstance will now create instances server-side with a RefCount=1, to allow passing self as an interface in sub-methods - see http://synopse.info/forum/viewtopic.php?id=961 |
---|---|
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA1: |
e2623df46f390a55982ff9ad4e0471ad |
User & Date: | abouchez 2012-12-06 13:20:29 |
2012-12-06
| ||
13:21 | included testing of interface based services in sicSingle mode check-in: 60ef888031 user: abouchez tags: trunk | |
13:20 | TServiceFactoryServerInstance will now create instances server-side with a RefCount=1, to allow passing self as an interface in sub-methods - see http://synopse.info/forum/viewtopic.php?id=961 check-in: e2623df46f user: abouchez tags: trunk | |
12:25 | added Owner, Actions and Events parameters to TSQLModel.Create() overloaded constructor check-in: 9b4ab9f114 user: abouchez tags: trunk | |
Changes to SQLite3/mORMot.pas.
695 696 697 698 699 700 701 702 703 704 705 706 707 708 .... 6184 6185 6186 6187 6188 6189 6190 6191 6192 6193 6194 6195 6196 6197 6198 6199 .... 6249 6250 6251 6252 6253 6254 6255 6256 6257 6258 6259 6260 6261 6262 6263 ..... 29223 29224 29225 29226 29227 29228 29229 29230 29231 29232 29233 29234 29235 29236 29237 ..... 29248 29249 29250 29251 29252 29253 29254 29255 29256 29257 29258 29259 29260 29261 29262 ..... 29268 29269 29270 29271 29272 29273 29274 29275 29276 29277 29278 29279 29280 29281 29282 ..... 29283 29284 29285 29286 29287 29288 29289 29290 29291 29292 29293 29294 29295 29296 29297 29298 29299 29300 29301 29302 29303 29304 29305 29306 29307 29308 29309 29310 29311 29312 ..... 29360 29361 29362 29363 29364 29365 29366 29367 29368 29369 29370 29371 29372 29373 29374 29375 29376 29377 29378 ..... 29386 29387 29388 29389 29390 29391 29392 29393 29394 29395 29396 29397 29398 29399 29400 ..... 29454 29455 29456 29457 29458 29459 29460 29461 29462 29463 29464 29465 29466 29467 29468 |
- new TInterfaceFactory.CreateFakeInstance() method for easy mocking of any interface, via some event callbacks - added TServiceMethod.DefaultResult property, to be used for stubs/mocks - TServiceFactory.Create() and its children will now always have an optional aContractExpected parameter (for consistency with TServiceFactoryClient) - introduce smvVariant kind of parameter for interface-based services - safer TInterfacedObjectFake.FakeCall() stack use - huge code refactoring of the ORM model implementation: a new dedicated TSQLModelRecordProperties will contain per-TSQLModel parameters, whereas shared information retrieved by RTTI remain in TSQLRecordProperties - this will allow use of the same TSQLRecord in several TSQLModel at once, with dedicated SQL auto-generation and external DB settings - added aExternalTableName/Database optional parameters to method TSQLModel.VirtualTableRegister() ................................................................................ public /// the internal Instance ID, as remotely sent in "id":1 // - is set to 0 when an entry in the array is free InstanceID: Cardinal; /// last time stamp access of this instance LastAccess: Cardinal; /// the implementation instance itself Instance: TObject; /// used to catch and ignore any exception in Instance.Free procedure SafeFreeInstance; end; /// server-side service provider uses this to store its internal instances // - used by TServiceFactoryServer in sicClientDriven, sicPerSession, // sicPerUser or sicPerGroup mode TServiceFactoryServerInstanceDynArray = array of TServiceFactoryServerInstance; ................................................................................ // for instance, ExecuteMethod(..,'[1,2]') over ICalculator.Add will return: // $ {"result":[3],"id":0} // the returned "id" number is the Instance identifier to be used for any later // sicClientDriven remote call - or just 0 in case of sicSingle or sicShared procedure ExecuteMethod(var Ctxt: TSQLRestServerCallBackParams; aMethodIndex, aInstanceID: cardinal; aParamsJSONArray: PUTF8Char); /// this method will create an implementation instance function CreateInstance: TInterfacedObject; public /// initialize the service provider on the server side // - expect an direct server-side implementation class (inheriting from // TInterfacedClass or from TInterfacedObjectWithCustomCreate if you need // an overriden constructor) // - for sicClientDriven, sicPerSession, sicPerUser or sicPerGroup modes, // a time out (in seconds) can be defined - if the time out is 0, interface ................................................................................ [InterfaceURI,fRest.ClassName]) else fImplementationClass := aImplementationClass; if fImplementationClass.InheritsFrom(TInterfacedObjectWithCustomCreate) then fImplementationClassWithCustomCreate := true; // initialize the shared instance or client driven parameters case InstanceCreation of sicShared: begin fSharedInstance := CreateInstance; if (fSharedInstance=nil) or not fSharedInstance.GetInterface(fInterface.fInterfaceIID,fSharedInterface) then raise EServiceException.CreateFmt('No implementation available for "%s" interface', [fInterfaceURI]); end; sicClientDriven, sicPerSession, sicPerUser, sicPerGroup: if aTimeOutSec=0 then ................................................................................ destructor TServiceFactoryServer.Destroy; var i: integer; begin try // release any internal instance (should have been done by client) for i := 0 to fInstancesCount-1 do if fInstances[i].Instance<>nil then fInstances[i].Instance.Free; except ; // better ignore any error in business logic code end; DeleteCriticalSection(fInstanceLock); inherited; end; ................................................................................ case fInstanceCreation of sicShared: if fSharedInterface<>nil then begin IInterface(Obj) := fSharedInterface; // copy implementation interface result := true; end; else begin O := CreateInstance; if O<>nil then result := O.GetInterface(fInterface.fInterfaceIID,Obj); end; end; end; function TServiceFactoryServer.RetrieveSignature: RawUTF8; ................................................................................ begin if self=nil then result := '' else result := Contract; // just return the current value end; procedure TServiceFactoryServerInstance.SafeFreeInstance; begin try InstanceID := 0; FreeAndNil(Instance); except ; // just ignore any error in customer code end; end; function TServiceFactoryServer.InternalInstanceRetrieve( var Inst: TServiceFactoryServerInstance; aMethodIndex: integer): boolean; procedure AddNew; var i: integer; P: ^TServiceFactoryServerInstance; begin Inst.Instance := CreateInstance; if Inst.Instance=nil then exit; P := pointer(fInstances); for i := 1 to fInstancesCount do if P^.InstanceID=0 then begin P^ := Inst; // found an empty entry -> use it exit; ................................................................................ end; function TServiceFactoryServer.RestServer: TSQLRestServer; begin result := TSQLRestServer(Rest); end; function TServiceFactoryServer.CreateInstance: TInterfacedObject; begin if fImplementationClassWithCustomCreate then result := TInterfacedObjectWithCustomCreateClass(fImplementationClass).Create else result := fImplementationClass.Create; end; procedure TServiceFactoryServer.ExecuteMethod( var Ctxt: TSQLRestServerCallBackParams; aMethodIndex, aInstanceID: cardinal; aParamsJSONArray: PUTF8Char); procedure Error(Msg: PUTF8Char); begin ................................................................................ // 1. initialize Inst.Instance and Inst.InstanceID Inst.InstanceID := 0; Inst.Instance := nil; case InstanceCreation of sicSingle: if aMethodIndex>=fInterface.fMethodsCount then exit else Inst.Instance := CreateInstance; sicShared: if aMethodIndex>=fInterface.fMethodsCount then exit else Inst.Instance := fSharedInstance; sicClientDriven, sicPerSession, sicPerUser, sicPerGroup: begin if InstanceCreation=sicClientDriven then Inst.InstanceID := aInstanceID else ................................................................................ Factory := nil; Session := nil; end; WR.Free; end; finally if InstanceCreation=sicSingle then Inst.Instance.Free; // always release single shot instance end; end; function TServiceFactoryServer.AllowAll: TServiceFactoryServer; var m: integer; begin if self<>nil then |
> > | | > > > > | | | | > < | | | | < | | > > | | |
695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 .... 6186 6187 6188 6189 6190 6191 6192 6193 6194 6195 6196 6197 6198 6199 6200 6201 6202 6203 .... 6253 6254 6255 6256 6257 6258 6259 6260 6261 6262 6263 6264 6265 6266 6267 6268 6269 ..... 29229 29230 29231 29232 29233 29234 29235 29236 29237 29238 29239 29240 29241 29242 29243 ..... 29254 29255 29256 29257 29258 29259 29260 29261 29262 29263 29264 29265 29266 29267 29268 ..... 29274 29275 29276 29277 29278 29279 29280 29281 29282 29283 29284 29285 29286 29287 29288 ..... 29289 29290 29291 29292 29293 29294 29295 29296 29297 29298 29299 29300 29301 29302 29303 29304 29305 29306 29307 29308 29309 29310 29311 29312 29313 29314 29315 29316 29317 ..... 29365 29366 29367 29368 29369 29370 29371 29372 29373 29374 29375 29376 29377 29378 29379 29380 29381 29382 29383 29384 29385 ..... 29393 29394 29395 29396 29397 29398 29399 29400 29401 29402 29403 29404 29405 29406 29407 ..... 29461 29462 29463 29464 29465 29466 29467 29468 29469 29470 29471 29472 29473 29474 29475 |
- new TInterfaceFactory.CreateFakeInstance() method for easy mocking of any interface, via some event callbacks - added TServiceMethod.DefaultResult property, to be used for stubs/mocks - TServiceFactory.Create() and its children will now always have an optional aContractExpected parameter (for consistency with TServiceFactoryClient) - introduce smvVariant kind of parameter for interface-based services - safer TInterfacedObjectFake.FakeCall() stack use - TServiceFactoryServerInstance will now create instances server-side with a RefCount=1, to allow passing self as an interface in sub-methods - huge code refactoring of the ORM model implementation: a new dedicated TSQLModelRecordProperties will contain per-TSQLModel parameters, whereas shared information retrieved by RTTI remain in TSQLRecordProperties - this will allow use of the same TSQLRecord in several TSQLModel at once, with dedicated SQL auto-generation and external DB settings - added aExternalTableName/Database optional parameters to method TSQLModel.VirtualTableRegister() ................................................................................ public /// the internal Instance ID, as remotely sent in "id":1 // - is set to 0 when an entry in the array is free InstanceID: Cardinal; /// last time stamp access of this instance LastAccess: Cardinal; /// the implementation instance itself Instance: TInterfacedObject; /// used to release the implementation instance // - direct FreeAndNil(Instance) may lead to A/V if self has been assigned // to an interface to any sub-method on the server side -> dec(RefCount) procedure SafeFreeInstance; end; /// server-side service provider uses this to store its internal instances // - used by TServiceFactoryServer in sicClientDriven, sicPerSession, // sicPerUser or sicPerGroup mode TServiceFactoryServerInstanceDynArray = array of TServiceFactoryServerInstance; ................................................................................ // for instance, ExecuteMethod(..,'[1,2]') over ICalculator.Add will return: // $ {"result":[3],"id":0} // the returned "id" number is the Instance identifier to be used for any later // sicClientDriven remote call - or just 0 in case of sicSingle or sicShared procedure ExecuteMethod(var Ctxt: TSQLRestServerCallBackParams; aMethodIndex, aInstanceID: cardinal; aParamsJSONArray: PUTF8Char); /// this method will create an implementation instance // - reference count will be set to one, in order to allow safe passing // of the instance into an interface, if AndIncreaseRefCount is TRUE function CreateInstance(AndIncreaseRefCount: boolean): TInterfacedObject; public /// initialize the service provider on the server side // - expect an direct server-side implementation class (inheriting from // TInterfacedClass or from TInterfacedObjectWithCustomCreate if you need // an overriden constructor) // - for sicClientDriven, sicPerSession, sicPerUser or sicPerGroup modes, // a time out (in seconds) can be defined - if the time out is 0, interface ................................................................................ [InterfaceURI,fRest.ClassName]) else fImplementationClass := aImplementationClass; if fImplementationClass.InheritsFrom(TInterfacedObjectWithCustomCreate) then fImplementationClassWithCustomCreate := true; // initialize the shared instance or client driven parameters case InstanceCreation of sicShared: begin fSharedInstance := CreateInstance(false); if (fSharedInstance=nil) or not fSharedInstance.GetInterface(fInterface.fInterfaceIID,fSharedInterface) then raise EServiceException.CreateFmt('No implementation available for "%s" interface', [fInterfaceURI]); end; sicClientDriven, sicPerSession, sicPerUser, sicPerGroup: if aTimeOutSec=0 then ................................................................................ destructor TServiceFactoryServer.Destroy; var i: integer; begin try // release any internal instance (should have been done by client) for i := 0 to fInstancesCount-1 do if fInstances[i].Instance<>nil then fInstances[i].SafeFreeInstance; except ; // better ignore any error in business logic code end; DeleteCriticalSection(fInstanceLock); inherited; end; ................................................................................ case fInstanceCreation of sicShared: if fSharedInterface<>nil then begin IInterface(Obj) := fSharedInterface; // copy implementation interface result := true; end; else begin O := CreateInstance(false); if O<>nil then result := O.GetInterface(fInterface.fInterfaceIID,Obj); end; end; end; function TServiceFactoryServer.RetrieveSignature: RawUTF8; ................................................................................ begin if self=nil then result := '' else result := Contract; // just return the current value end; procedure TServiceFactoryServerInstance.SafeFreeInstance; var Obj: TInterfacedObject; begin InstanceID := 0; Obj := Instance; Instance := nil; IInterface(Obj)._Release; end; function TServiceFactoryServer.InternalInstanceRetrieve( var Inst: TServiceFactoryServerInstance; aMethodIndex: integer): boolean; procedure AddNew; var i: integer; P: ^TServiceFactoryServerInstance; begin Inst.Instance := CreateInstance(true); if Inst.Instance=nil then exit; P := pointer(fInstances); for i := 1 to fInstancesCount do if P^.InstanceID=0 then begin P^ := Inst; // found an empty entry -> use it exit; ................................................................................ end; function TServiceFactoryServer.RestServer: TSQLRestServer; begin result := TSQLRestServer(Rest); end; function TServiceFactoryServer.CreateInstance(AndIncreaseRefCount: boolean): TInterfacedObject; begin if fImplementationClassWithCustomCreate then result := TInterfacedObjectWithCustomCreateClass(fImplementationClass).Create else result := fImplementationClass.Create; if AndIncreaseRefCount then IInterface(result)._AddRef; // allow passing self to sub-methods end; procedure TServiceFactoryServer.ExecuteMethod( var Ctxt: TSQLRestServerCallBackParams; aMethodIndex, aInstanceID: cardinal; aParamsJSONArray: PUTF8Char); procedure Error(Msg: PUTF8Char); begin ................................................................................ // 1. initialize Inst.Instance and Inst.InstanceID Inst.InstanceID := 0; Inst.Instance := nil; case InstanceCreation of sicSingle: if aMethodIndex>=fInterface.fMethodsCount then exit else Inst.Instance := CreateInstance(true); sicShared: if aMethodIndex>=fInterface.fMethodsCount then exit else Inst.Instance := fSharedInstance; sicClientDriven, sicPerSession, sicPerUser, sicPerGroup: begin if InstanceCreation=sicClientDriven then Inst.InstanceID := aInstanceID else ................................................................................ Factory := nil; Session := nil; end; WR.Free; end; finally if InstanceCreation=sicSingle then Inst.SafeFreeInstance; // always release single shot instance end; end; function TServiceFactoryServer.AllowAll: TServiceFactoryServer; var m: integer; begin if self<>nil then |