Skip to main content

Notice: this Wiki will be going read only early in 2024 and edits will no longer be possible. Please see: https://gitlab.eclipse.org/eclipsefdn/helpdesk/-/wikis/Wiki-shutdown-plan for the plan.

Jump to: navigation, search

Difference between revisions of "ECF/Asynchronous Remote Services"

< ECF
(Asynchronous Remote Services)
Line 1: Line 1:
 
[[ECF]]'s Remote Services API, which is used to implement OSGi remote services and remote service admin specifications, has the ability for consumers/clients to use asynchronous/non-block remote method calls.  
 
[[ECF]]'s Remote Services API, which is used to implement OSGi remote services and remote service admin specifications, has the ability for consumers/clients to use asynchronous/non-block remote method calls.  
  
===Normal/Synchronous OSGi (Remote) Services===
+
===Synchronous OSGi (Remote) Services===
  
 
When an OSGi service is actually invoked today, this is done by the caller calling a method on the service.  For example, consider a simple 'hello' service:
 
When an OSGi service is actually invoked today, this is done by the caller calling a method on the service.  For example, consider a simple 'hello' service:
Line 22: Line 22:
 
</source>
 
</source>
  
With OSGi remote services, this 'helloService' may actually be a proxy.  If invoked as above a proxy will marshall the method arguments (i.e. 'slewis' String in this case), and communicate with the remote service host via some network (i.e. via some protocol).  If there is a result of the call, then it will then be unmarshalled and returned to the caller thread.  With '''synchronous''' invocation the thread that calls 'hello' will block until this entire process is complete.
+
With OSGi remote services, this 'helloService' will typically be a proxy.  When invoked, the proxy will marshall the arguments (i.e. 'slewis' String in this case), communicate with the remote service host via some protocol.  If there is a result, then it will then be unmarshalled and returned to the caller thread on the consumer.  With '''synchronous''' invocation the thread that calls 'hello' will block until this entire process is complete and the return value is available.
  
 
===Asynchronous Remote Services===
 
===Asynchronous Remote Services===
  
ECF has added the ability to declare asynchronous access to a remote method, so that the consumer can ge guaranteed that calling the service will not block.  So, for example, it's now possible to make a non-blocking call to the hello service like this
+
ECF has added the ability to declare asynchronous access to a remote method, so that the consumer can ge guaranteed that calling the service will not block.  For example, it's now possible to make a non-blocking call to the hello service like this
  
 
<source lang="java">
 
<source lang="java">
Line 34: Line 34:
 
</source>
 
</source>
  
With an ECF created asynchronous proxy, the consumer thread that calls helloAsyncService.helloAsync is guaranteed '''not''' to block, and the returned Future
+
With an ECF created asynchronous proxy, the consumer thread that calls helloAsyncService.helloAsync is guaranteed '''not''' to block, and the returned Future&gt;String&lt;
can be used to access the value at some later point.
+
can be used to subsequently access the String result.
  
With ECF's asynchronous proxies, neither the consumer nor the host have to actually implement the asynchronous proxy behavior.  The proxy is automatically constructed by the ECF remote services implementation when accessed by a consumer.
+
With ECF's asynchronous proxy support, neither the consumer nor the host have to actually implement the asynchronous proxy.  The proxy is automatically constructed by the ECF remote services implementation.
  
At this point, you might ask:  But how is the asynchronous proxy defined?  i.e. where does the '''helloAsyncService''' come from?
+
At this point, you might ask:  How is the asynchronous proxy defined?  i.e. where does the '''helloAsyncService''' come from?
  
 
The answer to this is that it is defined in a new/second service interface...called the asynchronous service interface that is related to the '''IHello''' service interface:
 
The answer to this is that it is defined in a new/second service interface...called the asynchronous service interface that is related to the '''IHello''' service interface:
Line 82: Line 82:
 
</source>
 
</source>
  
Having both the synchronous (IHello) and asynchronous (IHelloAsync) service types gives the consumer maximum flexibility in determining how a given invocation will occur (i.e. synchronously or asynchronously).  Synchronous, asynchronous, or both invocation methods may be used.
+
Having both the synchronous (IHello) and asynchronous (IHelloAsync) service types gives the consumer flexibility in determining how a given remote invocation will occur (i.e. synchronously or asynchronously).  Synchronous, asynchronous, or both invocation methods may be used.
 
+
All that's required is for the service interface to declare an *Async service type class using these rules:
+
 
+
<ol>
+
<li>Class name must be <b>[service interface classname]Async</b>
+
<ul><li>Example:  <b>IHello -> IHelloAsync</b></li></ul></li>
+
<li>For any methods that should be exposed to the consumer via the asynchronous proxy
+
<ul>
+
<li>Name the method <b>[methodName]Async</b>
+
<ul><li>Example:  <b>hello -> helloAsync</b></li></ul></li>
+
<li>The return value should always be of type <b>java.util.concurrent.Future</b> with the actual return type via the Future generic type...e.g. Future<String></li>
+
</ul>
+
</li>
+
</ol>
+
  
 
====Java8's CompletableFuture====
 
====Java8's CompletableFuture====
  
With Java8's introduction of the class <b>java.util.concurrent.CompletableFuture</b> and ECF 3.8.1 remote services, it's now possible to have a CompletableFuture rather than a future returned by the ECF remote services proxy creation
+
With Java8's introduction of the class <b>java.util.concurrent.CompletableFuture</b> and ECF 3.8.1/Juno remote services, it's now possible to return a CompletableFuture rather than a Future in the asynchronous service interface:
=====Original Service Interface=====
+
<source lang="java">package org.eclipse.ecf.examples.remoteservices.hello;
+
  
public interface IHello {
 
 
public String hello(String from);
 
 
}
 
</source>
 
 
=====CompletableFuture Service Interface=====
 
=====CompletableFuture Service Interface=====
 
<source lang="java">package my.package;
 
<source lang="java">package my.package;
Line 120: Line 98:
 
</source>
 
</source>
  
This results in some very nice properties and runtime guarantees for remote service designers...the main one being that with CompletableFuture it's not necessary to call Future.get directly...but rather you can write nice, succinct and *guaranteed to be non-blocking and asynchronous* usage such as:
+
with CompletableFuture it's not necessary for the consumer to call Future.get (and possibly block) directly...but rather you can write succinct, simple, and '''guaranteed to be non-blocking''' remote service calls such as:
  
 
<source lang="java">
 
<source lang="java">
  
IHelloAsync helloAsync = ...get service via DS/injections, ServiceTracker or other
+
IHelloAsync helloAsync = ...get remote service via DS/injections, ServiceTracker or other
  
 
CompletableFuture<String> cf = helloAsync("slewis");
 
CompletableFuture<String> cf = helloAsync("slewis");
Line 132: Line 110:
 
</source>
 
</source>
  
The above code, while being very succinct has absolutely no blocking calls, meaning that consumers can be sure that the I/O and/or network traffic implementing the remote call will not block.
+
The use of CompletableFuture has some very nice properties for remote service design, as well as some nice guarantees for remote service consumer.  For remote service designers, they can declare and implement normal OSGi remote services (IHello) without having to even concern themselves with the consumer's invocation style (synchronous or asynchronous).
 +
 
 +
For remote service consumere, using Java8 CompletableFuture, they can be assured that there will be no blocking in their code (via the guarantees of CompletableFuture), use lambda to simply and succinctly express arbitrary code execution...guaranteed to be done asynchronously when the remote response becomes available.
  
 
==Notes==
 
==Notes==

Revision as of 18:29, 8 April 2014

ECF's Remote Services API, which is used to implement OSGi remote services and remote service admin specifications, has the ability for consumers/clients to use asynchronous/non-block remote method calls.

Synchronous OSGi (Remote) Services

When an OSGi service is actually invoked today, this is done by the caller calling a method on the service. For example, consider a simple 'hello' service:

package org.eclipse.ecf.examples.remoteservices.hello;
 
public interface IHello {
 
	public String hello(String from);
 
}

Once a consumer of this service gets a valid service reference (i.e. through ServiceTracker, injection via declarative services (DS) or other injection framework, BundleContext.getServiceReference or others), it can actually invoke/use the service:

String response = helloService.hello("slewis");

With OSGi remote services, this 'helloService' will typically be a proxy. When invoked, the proxy will marshall the arguments (i.e. 'slewis' String in this case), communicate with the remote service host via some protocol. If there is a result, then it will then be unmarshalled and returned to the caller thread on the consumer. With synchronous invocation the thread that calls 'hello' will block until this entire process is complete and the return value is available.

Asynchronous Remote Services

ECF has added the ability to declare asynchronous access to a remote method, so that the consumer can ge guaranteed that calling the service will not block. For example, it's now possible to make a non-blocking call to the hello service like this

Future<String> future = helloAsyncService.helloAsync("slewis");

With an ECF created asynchronous proxy, the consumer thread that calls helloAsyncService.helloAsync is guaranteed not to block, and the returned Future>String< can be used to subsequently access the String result.

With ECF's asynchronous proxy support, neither the consumer nor the host have to actually implement the asynchronous proxy. The proxy is automatically constructed by the ECF remote services implementation.

At this point, you might ask: How is the asynchronous proxy defined? i.e. where does the helloAsyncService come from?

The answer to this is that it is defined in a new/second service interface...called the asynchronous service interface that is related to the IHello service interface:

public interface IHelloAsync {
 
	public Future<String> helloAsync(String from);
}

Notice that this asynchronous service interface declaration resembles the IHello service interface declaration, but differs from it in several specific ways:

  1. The name is IHelloAsync rather than IHello
  2. The method name is helloAsync rather than hello
  3. The return value is Future<String> (or with Java8, CompletableFuture, see below)

With ECF remote services, when a IHello proxy is created, the proxy will also implement the IHelloAsync interface. So, for example

IHello helloService = ...get service via DS/injections, ServiceTracker or otherServiceTracker, or other...
if (helloService instanceof IHelloAsync) {
   IHelloAsync helloServiceAsync = (IHelloAsync) helloService;
   // call it asynchronously
   Future<String> future = helloAsync("slewis");
   // do other things
   String result = future.get();
   // do something with result...
}

or

IHelloAsync helloAsyncService = ...get service via DS/injections, ServiceTracker or other
// call it asynchronously...no blocking
Future<String> future = helloAsync("slewis");
// do other things
String result = future.get();
// do something with result...

Having both the synchronous (IHello) and asynchronous (IHelloAsync) service types gives the consumer flexibility in determining how a given remote invocation will occur (i.e. synchronously or asynchronously). Synchronous, asynchronous, or both invocation methods may be used.

Java8's CompletableFuture

With Java8's introduction of the class java.util.concurrent.CompletableFuture and ECF 3.8.1/Juno remote services, it's now possible to return a CompletableFuture rather than a Future in the asynchronous service interface:

CompletableFuture Service Interface
package my.package;
import java.util.concurrent.CompletableFuture;
 
public interface IHelloAsync {
 
    public CompletableFuture<String> hello(String from);
}

with CompletableFuture it's not necessary for the consumer to call Future.get (and possibly block) directly...but rather you can write succinct, simple, and guaranteed to be non-blocking remote service calls such as:

IHelloAsync helloAsync = ...get remote service via DS/injections, ServiceTracker or other
 
CompletableFuture<String> cf = helloAsync("slewis");
 
cf.thenAccept((response) -&gt; System.out.println("response to hello: " + response));

The use of CompletableFuture has some very nice properties for remote service design, as well as some nice guarantees for remote service consumer. For remote service designers, they can declare and implement normal OSGi remote services (IHello) without having to even concern themselves with the consumer's invocation style (synchronous or asynchronous).

For remote service consumere, using Java8 CompletableFuture, they can be assured that there will be no blocking in their code (via the guarantees of CompletableFuture), use lambda to simply and succinctly express arbitrary code execution...guaranteed to be done asynchronously when the remote response becomes available.

Notes


Eclipse Communication Framework
API
API DocumentationJavadocProviders
Development
Development GuidelinesIntegrators Guide

Copyright © Eclipse Foundation, Inc. All Rights Reserved.