#1 2016-01-19 12:40:48

jaclas
Member
Registered: 2014-09-12
Posts: 215

How to intercept call the methods of interface based service?

Hi,

I wanted to use Spring4D to use "virtual methods interceptor" (Nick Hodges presents it here https://www.youtube.com/watch?v=bjVKtac6bAY).
However, it failed, mORMot rejected my interface as incompatible with class (TInterfaceProxy from Spring4D, he is right).

Question:

Is there a way to intercept each method invocation (in interface based service) before and after the execution (on server side)?

Offline

#2 2016-01-19 13:12:28

ab
Administrator
From: France
Registered: 2010-06-21
Posts: 14,666
Website

Re: How to intercept call the methods of interface based service?

AFAIK there is no Spring.Interception unit in https://bitbucket.org/sglienke/spring4d
You need to use an unstable branch for the feature...

The TServiceFactoryServer.OnMethodExecute event is called before the execution of a method.
It allows to allow/deny execution of the given method.

Then you could use TServiceFactoryServer.SetServiceLog() which allows to log method execution information to a TSQLRecordServiceLog table.

Isn't it enough for you?

Offline

#3 2016-01-19 14:28:56

jaclas
Member
Registered: 2014-09-12
Posts: 215

Re: How to intercept call the methods of interface based service?

I do not use mORMot tables, an entire layer of DB I'm doing in my own code.
I would just access to BeforeExecute and AfterExecute events for the called service method.

Offline

#4 2016-01-19 14:54:22

ab
Administrator
From: France
Registered: 2010-06-21
Posts: 14,666
Website

Re: How to intercept call the methods of interface based service?

OK, but what is your exact need?
Security? parameters change? logging? ...?

Did you check TServiceFactoryServer.OnMethodExecute event and TServiceFactoryServer.SetServiceLog() function?

Offline

#5 2016-01-19 19:51:59

jaclas
Member
Registered: 2014-09-12
Posts: 215

Re: How to intercept call the methods of interface based service?

Yes, I check OnMethodExecute, but it's not enough.
I need:
- perform the measurement of the execution time of my methods and monitor the load of threads
- at the end of execute each service method I need to call a procedure notifying about who called the method (this procedure creates a data packet and puts it into the processing queue - it is kind of billing)

The service method interceptor would be ideal solution. And I know that you could do it quite easily ;-)

Offline

#6 2016-01-21 15:55:43

edwinsn
Member
Registered: 2010-07-02
Posts: 1,218

Re: How to intercept call the methods of interface based service?

@ab,  as a similar question, the last time you asked me to have created a ticket about intercepting all **exceptions** in a single place on the **client** side. Are you still interested in that ticket smile

http://synopse.info/fossil/tktview/f561 … a8ef19b2a4


Delphi XE4 Pro on Windows 7 64bit.
Lazarus trunk built with fpcupdelux on Windows with cross-compile for Linux 64bit.

Offline

#7 2016-01-23 22:11:44

ab
Administrator
From: France
Registered: 2010-06-21
Posts: 14,666
Website

Re: How to intercept call the methods of interface based service?

I've added OnBeforeURI, OnAfterURI and OnErrorURI event properties to TSQLRestServer.
It should fit your needs on server side.
See http://synopse.info/fossil/info/52698ae314

Offline

#8 2016-01-23 23:03:01

jaclas
Member
Registered: 2014-09-12
Posts: 215

Re: How to intercept call the methods of interface based service?

Big thanks Arnaud! :-)

Offline

#9 2016-01-23 23:12:11

ab
Administrator
From: France
Registered: 2010-06-21
Posts: 14,666
Website

Re: How to intercept call the methods of interface based service?

For the client side, I've added the TSQLRestClientURI.OnFailed centralized event.
See http://synopse.info/fossil/info/7c647a49d6

Offline

#10 2016-01-28 11:59:09

jaclas
Member
Registered: 2014-09-12
Posts: 215

Re: How to intercept call the methods of interface based service?

Hello,

I'm starting to use these events and came across a minor oversight ;-)

  TNotifyBeforeURI = function(Ctxt: TSQLRestServerURIContext): boolean;
  TNotifyAfterURI = procedure(Ctxt: TSQLRestServerURIContext);
  TNotifyErrorURI = function(Ctxt: TSQLRestServerURIContext; E: Exception): boolean;

Can you add at the end "of object"? :-)

Thx and regards

Last edited by jaclas (2016-01-28 11:59:32)

Offline

#11 2016-01-28 13:16:58

ab
Administrator
From: France
Registered: 2010-06-21
Posts: 14,666
Website

Re: How to intercept call the methods of interface based service?

Done by http://synopse.info/fossil/info/e89ca864f9

Sorry for the issue.

Offline

#12 2016-01-28 14:10:16

jaclas
Member
Registered: 2014-09-12
Posts: 215

Re: How to intercept call the methods of interface based service?

Thanks for fast fix.

But, I still have one small problem. You wrote in the documentation:

    /// event trigerred when URI() starts to process a request
    // - the supplied Ctxt parameter would give access to the command about to
    // be executed, e.g. Ctxt.Command=execSOAByInterface would identify a SOA
    // service execution, with the corresponding Service and ServiceMethodIndex
    // parameters as set by TSQLRestServerURIContext.URIDecodeSOAByInterface   <--- this method not exist in class
    // - should return TRUE if the method can be executed
    // - should return FALSE if the method should not be executed, and set the
    // corresponding error to the supplied context e.g.
    // ! Ctxt.Error('Unauthorized method',HTML_NOTALLOWED);
    // - since this callback would be executed during all TSQLRestServer.URI,
    // it should better not make any slow process (like writing to a remote DB)
    OnBeforeURI: TNotifyBeforeURI;

but I can't find this method. But nevermind, my question:

How can I find out what method and what parameters is called by client?
How get it from Ctxt: TSQLRestServerURIContext?

Last edited by jaclas (2016-01-28 14:10:44)

Offline

#13 2016-01-28 14:56:22

ab
Administrator
From: France
Registered: 2010-06-21
Posts: 14,666
Website

Re: How to intercept call the methods of interface based service?

URIDecodeSOAByInterface is defined as an abstract method in TSQLRestServerURIContext, and implemented depending on the REST routing used.
See http://synopse.info/files/html/Synopse% … #TITLE_437

Use the following properties of TSQLRestServerURIContext:

    /// the service identified by an interface-based URI
    Service: TServiceFactoryServer;
    /// the method index for an interface-based service
    // - Service member has already be retrieved from URI (so is not nil)
    // - 0..2 are the internal _free_/_contract_/_signature_ pseudo-methods
    ServiceMethodIndex: integer;
    /// the JSON array of parameters for an the interface-based service
    // - Service member has already be retrieved from URI (so is not nil)
    ServiceParameters: PUTF8Char;
    /// the instance ID for interface-based services instance
    // - can be e.g. the client session ID for sicPerSession or the thread ID for
    // sicPerThread
    ServiceInstanceID: cardinal;

Offline

#14 2016-01-28 19:23:28

jaclas
Member
Registered: 2014-09-12
Posts: 215

Re: How to intercept call the methods of interface based service?

I don't understand :-(
ServiceMethodIndex points to some array/list of methods? Where is this array/list?
Why ServiceParameters is nil in OnBeforeURI()?

jMF1PI99.png

Invoked method has 3 parameters.

Offline

#15 2016-01-28 20:06:10

jaclas
Member
Registered: 2014-09-12
Posts: 215

Re: How to intercept call the methods of interface based service?

Oh my god ... this is deeply buried :-)

It's OK? :

 sm := Ctxt.Service.InterfaceFactory.Methods[Ctxt.ServiceMethodIndex];

And how to get the value of any parameter?

Offline

#16 2016-01-28 21:34:47

ab
Administrator
From: France
Registered: 2010-06-21
Posts: 14,666
Website

Re: How to intercept call the methods of interface based service?

You can use Ctxt.Service.InterfaceFactory.Methods[Ctxt.ServiceMethodIndex] AFTER the method execution,
and Ctxt.Service.InterfaceFactory.Methods[Ctxt.ServiceMethodIndex-3] BEFORE method execution.

Offline

#17 2016-01-29 09:11:40

jaclas
Member
Registered: 2014-09-12
Posts: 215

Re: How to intercept call the methods of interface based service?

Thx for information.

I don't want to use hardcoded magic value, because it is dangerous (length SERVICE_PSEUDO_METHOD can change).
Can you add public function or class method:

function ServicePseudoMethodCount : Integer;
begin
 result := Length(SERVICE_PSEUDO_METHOD);
end;

And I refresh my previous question:

How to get the value of any parameter?

I tried various tricks, but without effect hmm

Offline

#18 2016-01-29 12:47:57

ab
Administrator
From: France
Registered: 2010-06-21
Posts: 14,666
Website

Re: How to intercept call the methods of interface based service?

When you asked for the callback, you did not mention anything about the parameters.
Is the "user" you wrote about part of the parameters?
Adding a call to your service counting, directly from the implementations methods may do better.
What we have implemented was a high-level hook, for all TSQLRestServer.URI requests (not only interface-based services, but also method-based services and ORM).

Having access to the parameters is tricky, since most of the data is translated directly from JSON into the binary representation in execution stack: it avoids intermediate conversions to TValue for instance (as regular RTTI.pas Invoke does), so uses less memory and allow to pass any kind of content.
So I see two possibilities:
- We may convert the input/output JSON parameters into two TDocVariant, from the input JSON, but it may be resource consuming.
- I guess that what we may also do is to add some other interface instance to be executed, before or after the execution. It would share the same execution stack, and interception code may be able to access the very same variables, on the fly. Execution time would be almost instant, but it may raise some border-side effects, and you would not be able to cancel the execution.
From my point of view, perhaps events with TDocVariant parameters may do the trick.

Offline

#19 2016-01-29 17:44:41

ab
Administrator
From: France
Registered: 2010-06-21
Posts: 14,666
Website

Re: How to intercept call the methods of interface based service?

I've added new

TServiceFactoryServer.AddInterceptor()

method and new

TServiceMethodExecute.Input/Output

properties.

They would allow to hook interface-based service execution, as you needed.

See http://synopse.info/fossil/info/20ea772181

Offline

#20 2016-01-31 14:42:44

jaclas
Member
Registered: 2014-09-12
Posts: 215

Re: How to intercept call the methods of interface based service?

Thanks again :-)
But... I well understand?
You're suggesting that I should use method AddInterceptor() RATHER than events OnBeforeURI and OnAfterURI? Because it looks that these solutions are interchangeable. That you mean?
I ask, because variety of solutions now surprised me :-)

best regards

Offline

#21 2016-01-31 16:16:29

ab
Administrator
From: France
Registered: 2010-06-21
Posts: 14,666
Website

Re: How to intercept call the methods of interface based service?

Yes, TServiceFactoryServer.AddInterceptor() should match your need much better than OnBeforeURI and OnAfterURI.

In practice, TServiceFactoryServer.AddInterceptor() is dedicated to interface-based services interception, whereas OnBeforeURI and OnAfterURI would be triggerred at lower level, for all kind of remote requests.
And TServiceFactoryServer.AddInterceptor()  gives you direct access to the executed method information: method name, and even parameters in Input/Output properties.

Offline

Board footer

Powered by FluxBB