Hi Mike,

Your interpretation of the behaviour described in the RFC is correct, including 
the roles of the mediator object and the async service. I’ll outline the design 
process that we went through, and hopefully that will answer your question.

One of the core problems associated with making this sort of asynchronous 
invocation is that you need to intercept a method call, immediately return a 
value that isn’t the real result, eventually provide the result through some 
other means.

It turns out that these requirements are very similar to those of a test 
mocking framework, for example Mockito. In Mockito you create a mock (or 
mediated) object, and the invocations made upon it are recorded. Configuring 
one of these mocks typically involves making the method call you wish to mock, 
e.g.

Mockito.when(mock.doStuff())…

This pattern works very well for the mediators produced by the Async Service 
too. The return type information from the mediator allows the generic type of 
the Promise to be determined. Given that the pattern was a natural fit, and the 
fact that mocking frameworks are widely used and understood, it was logical to 
reuse it.

In addition to the parallels with mocking, there were several other aspects.
The return value from a method call is rarely a Promise/Future,  which means 
that there must be some other mechanism to acquire the result. If the mediator 
calls directly began the asynchronous work then it would be easy to 
accidentally overwrite the Promise representing an earlier execution. The 
current API flow allows Async implementations to verify the API usage, and to 
throw exceptions if the mediator is used incorrectly.
Mediated objects are not thread safe, and should not be shared between bundles. 
The reason that they shouldn’t be shared is because they would allow other 
bundles to act using your bundle context. Requiring them to be used with the 
Async service encourages safer coding patterns.

In summary the mediated object isn’t actually a proxy (which is why we chose 
the method name mediate, rather than proxy). The mediator simply records the 
method calls made upon it, and has nothing to delegate to. The Async 
implementation is the service providing the asynchronous behaviour, which is 
why it is the one that gets called to begin the execution.

I hope that makes sense.

Regards,

Tim

On 14 Mar 2014, at 13:28, Mike Wilson <[email protected]> wrote:

> Async RFC 206 (from March 03) at:
> https://github.com/osgi/design/tree/master/rfcs/rfc0206
> 
> From section 5.4 we learn how to start an asynchronous
> invocation that has a return value:
> 
>  List asyncList = asyncService.mediate(listRef);
>  Promise<Boolean> promise = 
>    asyncService.call(asyncList.contains("badEntry"));
> 
> and one that has no return value (void method):
> 
>  mediator.clear();
>  Promise<Boolean> promise = asyncService.call();
> 
> The text explains that the actual asynchronous invocation 
> doesn't take place until calling Async.call(), ie:
> 
>  asyncService.call(asyncList.contains("badEntry"));
>               ^ send         ^ prepare
>                 async          async
>                 call           call
> 
>  asyncList.clear();          // prepare async call
>  asyncService.call();        // send async call
> 
> Why did you choose this design, and did not choose to
> let a proxied method send its own async call?
> 
> Best regards
> Mike
> 
> _______________________________________________
> OSGi Developer Mail List
> [email protected]
> https://mail.osgi.org/mailman/listinfo/osgi-dev

_______________________________________________
OSGi Developer Mail List
[email protected]
https://mail.osgi.org/mailman/listinfo/osgi-dev

Reply via email to