[
Date Prev][
Date Next][
Thread Prev][
Thread Next][
Date Index][
Thread Index]
[
List Home]
| [ecf-dev] a completable future for OSGi remote services | 
Hi Folks,
As some of you probably know, ECF has support for what we call 
'asynchronous proxies' [1].   What this allows is for consumers of 
remote services to use asynchronous/non-blocking invocation to access a 
remote service.
As a quick example...here's the time service interface that's used in 
our remote service tutorial [2]:
public interface ITimeService {
      public Long getCurrentTime();
}
As with any OSGi Remote Services, any consumer that discovers this 
service will potentially block when they call getCurrentTime(). This is 
just the nature of call/return semantics as applied to remoting...and so 
will be true for any implementation of OSGi remote services (not just of 
ECF's implementation).
ECF's impl of OSGi Remote Service offers asynchronous proxies, 
however...meaning that iff a second related service interface is 
defined...e.g.
public interface ITimeServiceAsync {
    public Future<Long> getCurrentTimeAsync();
}
then consumers will be able to use ITimeServiceAsync to access the 
service...e.g:
ITimeServiceAsync tsa = ... get ITimeServiceAsync reference
//
Future<Long> timeFuture = tsa.getCurrentTimeAsync();
...do work...
Long time = timeFuture.get();
With ECF 3.8.0 we further added [3]...i.e. the ability to have 
ITimeServiceAsync be registered as a service automatically (by ECF's 
remote services impl) on the consumer...so that (e.g.) the 
ITimeServiceAsync reference can be injected via ds...e.g.
...ds component...
void bindTimeServiceAsync(ITimeServiceAsync tsa) {
       ...use or store tsa...
}
This [3] is all available in ECF 3.8.0.   Note that the service 
interfaces have absolutely no reference to ECF classes, nor to OSGi 
classes.   None are needed now.
As many of you know...java8 just came out, and a big part of java8 is 
improved support for better concurrency, functional programming, and 
lambdas.    This better support for concurrency in java8 is potentially 
very useful for users of OSGi Remote Services.
I've been playing around with java8 api CompletableFuture, which as the 
name implies is a type of java.util.concurrent.Future.    It has some 
very nice properties for API/service designers...the main one being that 
it's not at all necessary to call Future.get directly...but rather you 
can write very nice/succinct and *guaranteed to be 
non-blocking/asynchronous* usage such as:
CompletableFuture<Long> cf = ...get CompletableFuture....
cf.thenAccept((time) -> System.out.println("time is: " + time));
This is very nice...because it's completely non-blocking 
(guaranteed)...and very succinct with use of lambda.  Also you can do 
really interesting things with chaining/filtering, etc., etc. All 
guaranteed to be non-blocking.
Yesterday I realized that with Java8, our asynchronous proxies could be 
generalized to allow something like this:
public interface ITimeServiceAsync {
public CompletableFuture<Long> getCurrentTimeAsync();
}
So I made some minor additions to the ECF remote service implementation 
of asynchronous proxies and now...with java8 obviously...this is 
working.   What I mean by this is that consumers of a remote service can 
now do this
...my service component....
void bindTimeServiceAsync(ITimeServiceAsync tsa) {
        // Get the CompletableFuture...no blocking here
        CompletableFuture<Long> cf = timeService.getCurrentTimeAsync();
        // print out time when done...no blocking anywhere!
        cf.thenAccept((time) -> System.out.println("Remote time is: " + 
time));
}
Note a few things:
1) There is no blocking anywhere in this code...guaranteed :). Even 
though the actual time value is retrieved via a remote OSGi service
2) The remote service host doesn't have to provide any implementation of 
ITimeServiceAsync.  It's constructed by ECF's RS impl automatically
3) It's also very easy to handle failure (e.g. network/io failure) via 
CompletableFuture.completeExceptionally.  This is obviously a big deal 
for remote services...which are much more inclined to fail because of 
network.
4) No reference to either OSGi or ECF classes anywhere in host or 
consumer code
1-4 is pretty nice for remote service consumers, IMHO...because it gives 
them strong no blocking guarantees, and can be very efficiently 
implemented (no additional threads) by remote service providers using 
asynchronous messaging (e.g. JMS, etc).   It also allows them to use all 
of CompletableFuture's APIs for chaining (see CompletableFuture javadoc).
This will obviously be part of ECF Luna...and I've created some test 
code (like above) that I intend to use to create another tutorial over 
the next month (before Luna).
The major drawback...for the time being...is that this does, of course, 
depend upon Java8...and so requires that both the remote service host 
and consumer use Java8, and that the remote service distribution 
provider be enhanced very slightly.   It's not technically challenging 
to make these enhancements, however.
Any thoughts/comments appreciated.
Thanks,
Scott
[1] https://wiki.eclipse.org/ECF/Asynchronous_Remote_Services
[2] 
https://wiki.eclipse.org/Tutorial:_Building_your_first_OSGi_Remote_Service
[3] https://bugs.eclipse.org/bugs/show_bug.cgi?id=420785