Author: pderop
Date: Tue Feb  2 23:35:22 2016
New Revision: 1728237

URL: http://svn.apache.org/viewvc?rev=1728237&view=rev
Log:
Updated CompletableFuture section.

Modified:
    
felix/site/trunk/content/documentation/subprojects/apache-felix-dependency-manager/guides/dm-lambda.mdtext

Modified: 
felix/site/trunk/content/documentation/subprojects/apache-felix-dependency-manager/guides/dm-lambda.mdtext
URL: 
http://svn.apache.org/viewvc/felix/site/trunk/content/documentation/subprojects/apache-felix-dependency-manager/guides/dm-lambda.mdtext?rev=1728237&r1=1728236&r2=1728237&view=diff
==============================================================================
--- 
felix/site/trunk/content/documentation/subprojects/apache-felix-dependency-manager/guides/dm-lambda.mdtext
 (original)
+++ 
felix/site/trunk/content/documentation/subprojects/apache-felix-dependency-manager/guides/dm-lambda.mdtext
 Tue Feb  2 23:35:22 2016
@@ -273,32 +273,82 @@ The available variety of factory methods
 
 ## CompletableFuture dependency.
 
-The new library provides a new feature; you can now make your component depend 
on the result of a jdk8 `CompletableFuture`.
+The new library provides a new feature which allows your component to depend 
on the result of a jdk8 `CompletableFuture`.
 CompletableFuture java8 class provides an asynchronous event-driven model and 
you can now define dependencies on any asynchronous events,
 like if they were service dependencies.
 
-Assume you develop an Http Service and you want to register it in the OSGi 
service registry only once the service is listening on port 80.
-Now, you want to use for example Vertx.io which allows to build reactive 
applications on the JVM. This library wraps asynchronous events behind a 
CompletableFuture.
+Let's explose this new dependency using an advanced example: assume you 
develop a component that needs to 
+track any "Tracked" services registered in the Registry, using a classic 
whiteboard pattern. But before, you need to
+download a web page at initialization, before you component is started. The 
downloaded webpage is required to be able to 
+handle Tracked services. Now, you don't want to block the initialization of 
your component (because in a reactive word,
+it is forbidden to block on the current thread.
+So, you use an HttpClient which allows to asynchronously download a web page, 
and when you schedule doGET() on the
+client, the method returns to you a `CompletableFuture<String>`.
 
-So, naturally, you can write from your init() method something like this:
+So, from your component init() method, you can just declare a FutureDependency 
on the result of the `CompletableFuture<String>`
+
+And once the result will be completed, you will then be called in your start() 
callback, and at this point, the Tracked services will then
+be injected (using DM, optional service callbacks are always invoked after the 
start() callback, never before).
+
+So, the Activator looks like this:
 
     :::java
-    public class HttpServiceImpl implements HttpService {
-        // lifecycle dm callback that allow you to add more dependencies
-        void init(Component c) { 
-            CompletableFuture<HttpServer> futureServer = 
createServer().listenFuture();
-            component(c, comp -> comp.withFuture(futureService, future -> 
future.cbi(this::serverReady)));
+    public class Activator extends DependencyActivatorBase {
+        @Override
+        public void init(BundleContext ctx, DependencyManager dm) throws 
Exception {
+            component(comp -> comp.impl(Pojo.class).provides(PojoService)
+               .withCnf("foo.pid").withSrv(HttpClient.class)
+               .withSrv(Tracked.class, srv -> 
srv.optional().cb(Pojo::bindTracked));
         }
+    }
+
+Now, here is the implementation for our component which downloads the URL from 
its init method. The init method will declare a "FutureDependency"
+for the result of the `CompletableFuture<String>` returned by the HttpClient. 
And once the result is injected
+in the setPage callback, then the start() callback will be called, and 
finally, any registered Tracked service will be
+injected in the "bindTracked" method:
+
+    :::java
+    import static org.apache.felix.dm.lambda.DependencyManagerActivator.*;
     
-        // Inject our HttpServer that is listening
-        void serverReady(HttpServer server) { ... }
+    public class Pojo implements PojoService {
+        HttpClient m_httpClient; // injected.
+        String m_url; // the URL to download using the http client.
+       
+        void updated(Dictionary<String, Object conf) throws Exception {
+            m_url = (String) conf.get("download.url");
+        }
+
+        // lifecycle dm callback that allows you to add more dependencies. 
start will be called once the webpage has been downloaded.
+        void init(Component c) {
+            // Let's schedule a download for our web page.
+            CompletableFuture<String> futurePage = m_httpClient.doGET(m_url);
     
+            // Add a required dependency to the result of the CF, and inject 
the result in our setPage method.
+            component(c, comp -> comp.withFuture(futurePage, future -> 
future.cbi(this::setPage)));
+        }
+    
+        void setPage(String content) {
+           // Called when the CompletableFuture has completed
+        }
+
         void start() {
-            // at this point we are fully started
-        }      
+                   // We have downloaded the page, our component is starting 
and is about to be registered
+        }
+
+        void bind(Tracked service) {
+            // a Tracked service is injected, we can handle it because we are 
fully initialized.
+            // (optional service callbacks are always invoked after the start 
callback).
+        }
     }
 
-and your HttpService will be call in `start` and registered only once the 
server is listening.
+So, using the Future Dependency we can nicely reuse the jdk CompletableFuture 
as a required dependency. Without using the FutureDependency
+on the CompletableFuture returned by the HttpClient, we would then have to 
manually register our service using bundleContext.registerService(), and we 
+would then have to check if the webpage has been downloaded each time a 
Tracked service is injected. And in case the page is not available, we would 
+then have to cache the injected Tracked service and process it later, once the 
page have been downloaded.
+
+Also, notice that when the page is injected in the setPage() method, you 
absolutely don't need to deal with
+synchronization at all because in DM, all lifecycle and dependency callbacks 
are safely scheduled in a "serial queue" associated to the
+component.
 
 ## Comparing two activators using old and new API:
 


Reply via email to