Author: pderop
Date: Wed Feb 24 00:14:11 2016
New Revision: 1731996

URL: http://svn.apache.org/viewvc?rev=1731996&view=rev
Log:
updated dm-lambda doc.

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=1731996&r1=1731995&r2=1731996&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
 Wed Feb 24 00:14:11 2016
@@ -72,7 +72,7 @@ Now, let's rework the above example, usi
             // Declare our Consumer component
     
             component(comp -> comp.impl(ServiceConsumer.class)
-                .withSvc(ServiceProvider.class, srv -> 
srv.filter("(p1=v1)").add(ServiceConsumer::setProvider))
+                .withSvc(ServiceProvider.class, svc -> 
svc.filter("(p1=v1)").add(ServiceConsumer::setProvider))
                 .withCnf(ServiceConsumer.class.getName()));
                 
             // Declare our ServiceProvider service component:
@@ -153,7 +153,7 @@ The following is the same as above, usin
         }
     }
 
-And to reduce the "code ceremony", here is a more concise version where the 
type of the lambda parameter is not declared:
+Here is a more concise version with less "code ceremony" where the type of the 
type of the lambda parameter is not declared:
 
     :::java
     import org.apache.felix.dm.lambda.DependencyManagerActivator;
@@ -165,10 +165,14 @@ And to reduce the "code ceremony", here
         }
     }
 
-## Adding service dependencies
+## Adding service dependencies injected in class fields.
 
-You can add a dependency using the `withSvc` methods available from the 
ComponentBuilder interface.
+You can add a dependency using the "`withSvc`" methods available from the 
ComponentBuilder interface.
 Such method accepts a `Consumer<ServiceDependencyBuilder>` lambda expression, 
which may then configure the dependency using a chain of method calls 
(filter/callbacks,autoconfig, etc ...):
+When you don't specify callbacks, services are injected in class fields with 
compatible service dependency type, but you can specify a field name.
+Unavailable optional dependencies are injected as "`Null Objects`".
+
+The following example adds a service dependency on a LogService with a service 
filter.
 
     :::java
     import org.apache.felix.dm.lambda.DependencyManagerActivator;
@@ -178,11 +182,11 @@ Such method accepts a `Consumer<ServiceD
         @Override
         public void init(BundleContext ctx, DependencyManager dm) throws 
Exception {
             component(comp -> comp.impl(Hello.class)
-                .withSvc(LogService.class, (ServiceDependencyBuilder srv) -> 
srv.filter("(vendor=apache)")));
+                .withSvc(LogService.class, (ServiceDependencyBuilder svc) -> 
svc.filter("(vendor=apache)")));
         }
     }
 
-The above example adds a service dependency on a LogService with a service 
filter. Here is a more concise version where the type of the `srv` lambda 
parameter is not declared:
+Here is a more concise version where the type of the `svc` lambda parameter is 
not declared:
 
     :::java
     import org.apache.felix.dm.lambda.DependencyManagerActivator;
@@ -190,7 +194,7 @@ The above example adds a service depende
     public class Activator extends DependencyManagerActivator {
         @Override
         public void init(BundleContext ctx, DependencyManager dm) throws 
Exception {
-            component(comp -> comp.impl(Hello.class).withSvc(LogService.class, 
srv -> srv.filter("(vendor=apache)")));
+            component(comp -> comp.impl(Hello.class).withSvc(LogService.class, 
svc -> svc.filter("(vendor=apache)")));
         }
     }
 
@@ -222,10 +226,25 @@ dependency that is not needing a Service
         }
     }
 
-## Service Dependency Component callbacks
+Dependency services can be injected in the following kind of fields:
+
+- a field having the same type as the dependency. If the field may be accessed 
by anythread, then the field should be declared 
+volatile, in order to ensure visibility when the field is auto injected 
concurrently.
+- a field which is assignable to an `Iterable<T>` where T must match the 
dependency type. In this case, an Iterable will be 
+injected by DependencyManager before the start callback is called. The 
Iterable field may then be traversed to inspect the 
+currently available dependency services. The Iterable can possibly be set to a 
final value so you can choose the Iterable implementation of your choice (for 
example, a CopyOnWrite ArrayList, or a ConcurrentLinkedQueue).
+- a `Map<K,V>` where K must match the dependency type and V must exactly 
equals Dictionary class. In this case, a 
+ConcurrentHashMap will be injected by DependencyManager before the start 
callback is called. 
+The Map may then be consulted to lookup current available dependency services, 
including the dependency service properties 
+(the map key holds the dependency services, and the map value holds the 
dependency service properties). 
+The Map field may be set to a final value so you can choose a Map of your 
choice (Typically a ConcurrentHashMap). 
+A ConcurrentHashMap is "weakly consistent", meaning that when traversing the 
elements, you may or may not see any concurrent 
+updates made on the map. So, take care to traverse the map using an iterator 
on the map entry set, 
+which allows to atomically lookup pairs of Dependency service/Service 
properties. 
+
+## Service Dependency callbacks
 
-By default, service dependencies are auto injected in class fields (you can 
configure the name of the class field where the dependency should be injected).
-But like in the current DM API, you can specify callbacks on the component 
implementation class using the "`add/change/remove/swap`" 
`ServiceDependencyBuilder` methods:
+You can specify callbacks on the component implementation class using the 
"`add/change/remove/swap`" `ServiceDependencyBuilder` methods:
 
     :::java
     import org.apache.felix.dm.lambda.DependencyManagerActivator;
@@ -233,7 +252,7 @@ But like in the current DM API, you can
     public class Activator extends DependencyManagerActivator {
         @Override
         public void init(BundleContext ctx, DependencyManager dm) throws 
Exception {
-            component(comp -> comp.impl(Hello.class).withSvc(LogService.class, 
srv -> srv.add("setLog")));
+            component(comp -> comp.impl(Hello.class).withSvc(LogService.class, 
svc -> svc.add("setLog")));
         }
     }
 
@@ -245,7 +264,7 @@ Now you can also use a more type-safe ca
     public class Activator extends DependencyManagerActivator {
         @Override
         public void init(BundleContext ctx, DependencyManager dm) throws 
Exception {
-            component(comp -> comp.impl(Hello.class).withSvc(LogService.class, 
srv -> srv.add(Hello::setLog)));
+            component(comp -> comp.impl(Hello.class).withSvc(LogService.class, 
svc -> svc.add(Hello::setLog)));
         }
     }
 
@@ -257,7 +276,7 @@ or:
     public class Activator extends DependencyManagerActivator {
         @Override
         public void init(BundleContext ctx, DependencyManager dm) throws 
Exception {
-            component(comp -> comp.impl(Hello.class).withSvc(LogService.class, 
srv -> srv.add(Hello::setLog).remove(Hello::unsetLog)));
+            component(comp -> comp.impl(Hello.class).withSvc(LogService.class, 
svc -> svc.add(Hello::setLog).remove(Hello::unsetLog)));
         }
     }
 
@@ -293,7 +312,7 @@ For example, the following example injec
         @Override
         public void init(BundleContext ctx, DependencyManager dm) throws 
Exception {
             DependencyHandler depHandler = new DependencyHandler();
-            component(comp -> comp.impl(Hello.class).withSvc(LogService.class, 
srv -> srv.add(depHandler, "setLog")));
+            component(comp -> comp.impl(Hello.class).withSvc(LogService.class, 
svc -> svc.add(depHandler, "setLog")));
         }
     }
 
@@ -306,7 +325,7 @@ or using method reference:
         @Override
         public void init(BundleContext ctx, DependencyManager dm) throws 
Exception {
             DependencyHandler depHandler = new DependencyHandler();
-            component(comp -> comp.impl(Hello.class).withSvc(LogService.class, 
srv -> srv.add(depHandler::setLog)));
+            component(comp -> comp.impl(Hello.class).withSvc(LogService.class, 
svc -> svc.add(depHandler::setLog)));
         }
     }
 
@@ -319,7 +338,7 @@ You can chain multiple callbacks:
         @Override
         public void init(BundleContext ctx, DependencyManager dm) throws 
Exception {
             DependencyHandler depHandler = new DependencyHandler();
-            component(comp -> comp.impl(Hello.class).withSvc(LogService.class, 
srv -> srv.add(Hello::setLog).add(depHandler::setLog)));
+            component(comp -> comp.impl(Hello.class).withSvc(LogService.class, 
svc -> svc.add(Hello::setLog).add(depHandler::setLog)));
         }
     }
 
@@ -479,7 +498,7 @@ what it has parsed, it will possibly add
             parseXml(conf.get("some.xml.configuration"));
         }
     
-        void init(Component c) { // lifecycle dm callback that allow you to 
add more dependencies
+        void init(Component c) { // lifecycle dm callback that allows you to 
add more dependencies
             if (xmlConfigurationRequiresEventAdmin) {
                 component(c, comp -> comp.withSvc(EventAdmin.class));
             }
@@ -524,18 +543,18 @@ And an example where you create a new DM
 
 ## Creating Aspect Components
 
-Like with the original DM API, you can create aspects (service interceptors), 
using the "`aspect`" factory method.
+Like with the original DM API, you can create a chain of aspects (service 
interceptors) ordered by a ranking attribute, using the "`aspect`" factory 
method.
 This method accepts in argument a ServiceAspectBuilder.
 
 Code example which provides a "LogService" aspect that performs spell-checking 
of each log message. The aspect decorates a LogService. 
-The aspect also depends on an Dictionary service that is internally used to 
perform log spell checking. 
-The LogService and Dictionary services are injected in the aspect 
implementation using reflection on class 
+The aspect also depends on a DictionaryService that is internally used to 
perform log spell checking. 
+The LogService and DictionaryService services are injected in the aspect 
implementation using reflection on class 
 fields:
 
     ::::java
     public class Activator extends DependencyManagerActivator {
         public void init(BundleContext ctx, DependencyManager dm) throws 
Exception { 
-            aspect(LogService.class, (ServiceAspectBuilder asp) -> 
asp.impl(SpellCheckLogAspect.class).rank(10).withSvc(Dictionary.class));
+            aspect(LogService.class, (ServiceAspectBuilder asp) -> 
asp.impl(SpellCheckLogAspect.class).rank(10).withSvc(DictionaryService.class));
         }
     } 
 
@@ -544,11 +563,11 @@ Same more concise example which does not
     ::::java
     public class Activator extends DependencyManagerActivator {
         public void init(BundleContext ctx, DependencyManager dm) throws 
Exception { 
-            aspect(LogService.class, asp -> 
asp.impl(SpellCheckLogAspect.class).rank(10).withSvc(Dictionary.class));
+            aspect(LogService.class, asp -> 
asp.impl(SpellCheckLogAspect.class).rank(10).withSvc(DictionaryService.class));
         }
     } 
 
-Same example, but using callbacks for injecting LogService and Dictionary 
services in the aspect implementation class:
+Same example, but using callbacks for injecting LogService and 
DictionaryService in the aspect implementation class:
 
     :::java
     public class Activator extends DependencyManagerActivator {
@@ -556,7 +575,7 @@ Same example, but using callbacks for in
            aspect(LogService.class, asp -> asp
               .impl(SpellCheckLogAspect.class).rank(10)
               .add(SpellCheckLogAspect::setLogService)
-              .withSvc(Dictionary.class, svc -> 
svc.add(SpellCheckLogAspect::setDictionary)));
+              .withSvc(DictionaryService.class, svc -> 
svc.add(SpellCheckLogAspect::setDictionary)));
         }
     } 
 
@@ -584,6 +603,39 @@ Same more concise example which does not
         }
     }
 
+## Creating Factory Configuration Adapter Components
+
+A Factory Configuration Adapter allows to create many instances of the same 
service, each time a configuration instance is created for a given factory pid.
+To declare a factory pid configuration adapter, use the `factoryPid` method 
available from the DependencyManagerActivator class and pass to it
+a lambda for the FactoryPidAdapterBuilder argument:
+
+Example that defines a factory configuration adapter service for the "foo.bar" 
factory pid. For each factory pid instance, an instance of the DictionaryImpl 
component will be created:
+
+    :::java
+    public class Activator extends DependencyManagerActivator {
+        public void init(BundleContext ctx, DependencyManager dm) throws 
Exception { 
+           factoryPidAdapter(adapter -> adapter
+              
.impl(DictionaryImpl.class).factoryPid("foo.bar").propagate().update(ServiceImpl::updated)
+              .withSvc(LogService.class, log -> log.optional()));
+        }
+    }
+
+Example that defines a factory configuration adapter using a user defined 
configuration type (the pid is by default assumed to match the fqdn of the 
configuration type):
+
+    :::java 
+    public interface DictionaryConfiguration {
+        public String getLanguage();
+        public List<String> getWords();
+    }
+
+    public class Activator extends DependencyManagerActivator {
+        public void init(BundleContext ctx, DependencyManager dm) throws 
Exception { 
+            factoryPidAdapter(adapter -> adapter
+                
.impl(DictionaryImpl.class).factoryPid("foo.bar").propagate().update(DictionaryConfiguration.class,
 ServiceImpl::updated)               
+                .withSvc(LogService.class, log -> log.optional()));
+        }
+    }
+
 ## Creating a Bundle Adapter component
 
 A Bundle Adapter is used to create a Component when a bundle that matches a 
given filter is found.
@@ -596,16 +648,11 @@ Example that creates a BundleAdapter ser
     public class Activator extends DependencyManagerActivator {
         public void init(BundleContext ctx, DependencyManager dm) throws 
Exception { 
            bundleAdapter(adapt -> adapt
-               .impl(BundleAdapterImpl.class)
-               .provides(BundleAdapter.class)
-               .mask(Bundle.INSTALLED | Bundle.RESOLVED | Bundle.ACTIVE)
+               
.impl(BundleAdapterImpl.class).provides(BundleAdapter.class).mask(Bundle.INSTALLED|Bundle.RESOLVED|Bundle.ACTIVE)
               
                .add(BundleAdapterImpl::bundleStarted)
-               .withSvc(LogService.class, "(vendor=apache)")
-               .withSvc(EventAdmin.class, ConfigurationAdmin.class));
+               .withSvc(LogService.class, "(vendor=apache)"));              
         }
     }
- 
-Notice that the adapter also depends on three services (LogService, 
EventAdmin, and ConfigurationAdmin services).
 
 ## CompletableFuture dependency.
 
@@ -635,7 +682,7 @@ So, the Activator looks like this:
         @Override
         public void init(BundleContext ctx, DependencyManager dm) throws 
Exception {
             component(comp -> comp.impl(Pojo.class).provides(PojoService)
-               
.withCnf("foo.pid").withSvc(HttpClient.class).withSvc(Tracked.class, srv -> 
srv.optional().add(Pojo::bindTracked));
+               
.withCnf("foo.pid").withSvc(HttpClient.class).withSvc(Tracked.class, svc -> 
svc.optional().add(Pojo::bindTracked));
         }
     }
 
@@ -680,7 +727,7 @@ injected in the "bindTracked" method:
     }
 
 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 
+on the CompletableFuture returned by the HttpClient, we would then have to 
manually register our service using bundleContext.registerService (once the web 
page has been downloaded), 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 has been downloaded.
 


Reply via email to