felix-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From pde...@apache.org
Subject svn commit: r1731482 - /felix/site/trunk/content/documentation/subprojects/apache-felix-dependency-manager/guides/dm-lambda.mdtext
Date Sat, 20 Feb 2016 21:53:18 GMT
Author: pderop
Date: Sat Feb 20 21:53:18 2016
New Revision: 1731482

URL: http://svn.apache.org/viewvc?rev=1731482&view=rev
Log:
Updated documentation.

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=1731482&r1=1731481&r2=1731482&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
Sat Feb 20 21:53:18 2016
@@ -2,29 +2,99 @@ Title: Dependency Manager Lambda
 
 ----------
 
+**Welcome to Felix Dependency Manager Lambda.**
 
-Since the R7 version, a new dm-lambda library has been introduced in the DM distribution.
This new library allows to programmatically declare OSGi components
-using a bit more fluent, concise and type-safe API that is based on Java8 Lambda expressions
and other goodies like method references.
-
-(Please notice that using the dm-lambda library requires the usage of a recent Java8 jvm
(the library has been tested with java version "1.8.0_71").
+## Introduction
 
-## Principle
+Since the R7 version, a new dm-lambda library has been introduced in the DM distribution.
This new library allows to programmatically declare OSGi components
+using a new style based on java8 lambda expressions and other goodies like method references.
 
 The new library is based on the `builder` design pattern applied to java8 lambdas. Basically,
you call a chain of methods from a 
 fluent `builder`, and at the end of the chain, you call "`build()`" which returns the actual
DM objects that you already know from 
 the original DM API. 
-We'll see later that using lambdas avoids the call to the last "`build`" method and adds
the constructed DM Component into the 
-DependencyManager object automatically.
+We'll see later that using lambdas avoids to call the last "`build`" method and allows to
automatically add the constructed DM Component into the 
+DependencyManager object.
+
+Please notice that using the dm-lambda library requires the usage of a recent Java8 jvm (the
library has been tested with java version "1.8.0_71").
+
+## Comparing two activators using old and new API:
+
+Before presenting the new API, let's get a jump start and dive into a comparison between
the old and new API: assume we have a `ServiceConsumer` which depends on the following services:
+
+- a required dependency on `ServiceProvider` service  with a "`(p1=v1)`" filter. The dependency
is injected in the "`ServiceConsumer.setProvider()`" method.
+- a Configuration with pid="`org.apache.felix.dm.lambda.samples.hello.ServiceConsumer`".
+
+Now assume we have `ServiceProvider` provided with p1="v1" and p2=123 service properties;
and the provider also depends on:
+
+- a required `LogService` service (injected in class fields).
+- a required `EventAdmin` service  (injected in class fields).
+
+Then we have the following typical Activator (we define both components in the same Activator
for simplicity):
+
+    import org.apache.felix.dm.DependencyActivatorBase;
+    ...
+
+    :::java
+    public class Activator extends DependencyActivatorBase {
+        @Override
+        public void init(BundleContext ctx, DependencyManager dm) throws Exception {
+            // Declare our Consumer component
+    
+            Component consumer = dm.createComponent()
+    	        .setImplementation(ServiceConsumer.class)
+                .add(createServiceDependency().setService(ServiceProvider.class, "(p1=v1)").setRequired(true).setCallbacks("setProvider",
null))
+                .add(createConfigurationDependency().setPid(ServiceConsumer.class.getName()));
+            dm.add(consumer);
+    
+           // Declare our ServiceProvider service component
+    
+    	   Properties properties = new Properties();
+    	   Properties.put("p1", "v1");
+    	   properties.put("p2", 123);
+           Component provider = dm.createComponent()
+       	       .setImplementation(ServiceProviderImpl.class)
+    	       .setInterface(ServiceProvider.class.getName(), properties)
+    	       .add(createServiceDependency().setService(LogService.class).setRequired(true))
+    	       .add(createServiceDependency().setService(EventAdmin.class, null).setRequired(true));
+           dm.add(provider);
+        }
+    }
+
+Now, let's rework the above example, using the new dm-lambda API:
+
+    :::java
+    import org.apache.felix.dm.lambda.DependencyManagerActivator;
+    ...
+
+    public class Activator extends DependencyManagerActivator {
+        @Override
+        public void init(BundleContext ctx, DependencyManager dm) throws Exception {
+            // Declare our Consumer component
+    
+            component(comp -> comp.impl(ServiceConsumer.class)
+                .withSvc(ServiceProvider.class, srv -> srv.filter("(p1=v1)").add(ServiceConsumer::setProvider))
+                .withCnf(ServiceConsumer.class.getName()));
+                
+            // Declare our ServiceProvider service component:
+    
+            component(comp -> comp.impl(ServiceProviderImpl.class)
+                .provides(ServiceProvider.class, p1 -> "v1", p2 -> 123)
+                .withSvc(LogService.class, EventAdmin.class));
+    }
+
+(all dependencies are required by default, if they are not explicitly declared as optional
or required).
+
+# Principle
 
-The new API is provided by the `org.apache.felix.dependencymanager.lambda.jar` bundle. the
following builders are currently supported:
+The new API is provided by the `org.apache.felix.dependencymanager.lambda.jar` bundle. The
following builders are currently supported:
 
-- ComponentBuilder: it is used to build some instances of the org.apache.felix.dm.Component
interface.
-- ServiceDependencyBuilder: builds some instances of org.apache.felix.dm.ServiceDependency.
-- ConfigurationDependencyBuiler: builds some instances of org.apache.felix.dm.ConfigurationDependency.
-- BundleAdapterBuilder: builds some DM bundle adapters.
-- ServiceAdapterBuilder.java: builds some instances of DM service adapters.
-- FactoryPidAdapterBuilder: builds some instances of DM factory pid adapters.
-- FutureDependencyBuilder: it's a new feature, allowing to "wait for" an asynchronous event
represented by a standard jdk8 `CompletableFuture` object.
+- ComponentBuilder: it is used to build org.apache.felix.dm.Component from original DM API.
+- ServiceDependencyBuilder: builds org.apache.felix.dm.ServiceDependency from original DM
API.
+- ConfigurationDependencyBuiler: builds org.apache.felix.dm.ConfigurationDependency from
original DM API.
+- BundleAdapterBuilder: builds a bundle adapter component from the original DM API.
+- ServiceAdapterBuilder.java: builds a DM service adapter from the original DM API.
+- FactoryPidAdapterBuilder: builds a DM factory pid adapter from the original DM API.
+- FutureDependencyBuilder: it's a new feature allowing to "wait for" an asynchronous event
represented by a standard jdk8 `CompletableFuture` object.
 
 (There is currently no builders for DM ResourceDependency and ResourceAdapter objects, but
they will be supported soon).
 
@@ -40,10 +110,9 @@ for dm-lambda activators:
 
     public class Activator extends DependencyManagerActivator {
         @Override
-        public void activate() throws Exception {
+        public void init(BundleContext ctx, DependencyManager dm) throws Exception {
             ComponentBuilder builder = component();
             Component comp = builder.impl(Hello.class).build();
-            DependencyManager dm = getDM();
     	    dm.add(comp);
         }
     }
@@ -58,9 +127,9 @@ Here is a shorter version:
 
     public class Activator extends DependencyManagerActivator {
         @Override
-        public void activate() throws Exception {
+        public void init(BundleContext ctx, DependencyManager dm) throws Exception {
             Component comp = component().impl(Hello.class).build());
-            getDM().add(comp);
+            dm.add(comp);
         }
     }
 
@@ -79,30 +148,26 @@ The following is the same as above, usin
 
     public class Activator extends DependencyManagerActivator {
         @Override
-        public void activate() throws Exception {
+        public void init(BundleContext ctx, DependencyManager dm) throws Exception {
             component((ComponentBuilder comp) -> comp.impl(Hello.class));
         }
     }
 
-And here is a more concise version where the type of the lambda parameter is not declared:
+And to reduce the "code ceremony", here is a more concise version where the type of the lambda
parameter is not declared:
 
     :::java
     import org.apache.felix.dm.lambda.DependencyManagerActivator;
 
     public class Activator extends DependencyManagerActivator {
         @Override
-        public void activate() throws Exception {
+        public void init(BundleContext ctx, DependencyManager dm) throws Exception {
             component(comp -> comp.impl(Hello.class));
         }
     }
 
-## Javadoc 
-
-You can find the javadoc for the new Dependency Manager Lambda library [here](../../../../apidocs/).
-
 ## Adding service dependencies
 
-Service Dependencies, unlike in the original DM API, are required by default, and you can
add a dependency using the `withSrv` 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 ...):
 
     :::java
@@ -111,9 +176,9 @@ Such method accepts a `Consumer<ServiceD
 
     public class Activator extends DependencyManagerActivator {
         @Override
-        public void activate() throws Exception {
+        public void init(BundleContext ctx, DependencyManager dm) throws Exception {
             component(comp -> comp.impl(Hello.class)
-                .withSrv(LogService.class, (ServiceDependencyBuilder srv) -> srv.filter("(vendor=apache)")));
+                .withSvc(LogService.class, (ServiceDependencyBuilder srv) -> srv.filter("(vendor=apache)")));
         }
     }
 
@@ -124,64 +189,53 @@ The above example adds a service depende
 
     public class Activator extends DependencyManagerActivator {
         @Override
-        public void activate() throws Exception {
-            component(comp -> comp.impl(Hello.class).withSrv(LogService.class, srv ->
srv.filter("(vendor=apache)")));
+        public void init(BundleContext ctx, DependencyManager dm) throws Exception {
+            component(comp -> comp.impl(Hello.class).withSvc(LogService.class, srv ->
srv.filter("(vendor=apache)")));
         }
     }
 
-If you depend on multiple required services (without filters), you can declare the services
in one shot like this:
+If you depend on multiple services (without filters), you can declare the services in one
shot like this
+(the dependencies will be injected in compatible class fields, by reflection):
 
     :::java
     import org.apache.felix.dm.lambda.DependencyManagerActivator;
 
     public class Activator extends DependencyManagerActivator {
         @Override
-        public void activate() throws Exception {
+        public void init(BundleContext ctx, DependencyManager dm) throws Exception {
             // using a varargs of service dependencies ...
-            component(comp -> comp.impl(Hello.class).withSrv(LogService.class, EventAdmin.class));

+            component(comp -> comp.impl(Hello.class).withSvc(LogService.class, EventAdmin.class));

         }
     }
 
-## Service Dependency Component 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 "`cb`" `ServiceDependencyBuilder` method:
+When you want to inject a service in a class field, but using a filter, you can also define
a one-liner 
+dependency that is not needing a ServiceDependencyBuilder lambda:
 
     :::java
     import org.apache.felix.dm.lambda.DependencyManagerActivator;
 
     public class Activator extends DependencyManagerActivator {
         @Override
-        public void activate() throws Exception {
-            component(comp -> comp.impl(Hello.class).withSrv(LogService.class, srv ->
srv.cb("setLog")));
+        public void init(BundleContext ctx, DependencyManager dm) throws Exception {
+            // using a varargs of service dependencies ...
+            component(comp -> comp.impl(Hello.class).withSvc(LogService.class, "(vendor=apache)"));

         }
     }
 
-The `cb` method accepts a varargs of strings (up to 4 method names):
+## Service Dependency Component callbacks
 
-1. when using one argument, it is used as the `add` callback.
-1. when using two arguments, the first arg is used as the `add` callback, and the second
one as the `remove` callback.
-1. when using three arguments, the first arg is used as the `add` callback, the second one
as the `change` callback, and the third one as the `remove` callback.
-1. when using four arguments, the first arg is used as the `add` callback, the second one
as the `change` callback, the third one as the `remove` callback, and the last one as the
`swap` callback.
+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:
 
-The add/change/remove callbacks accept the following kind of method signatures ("S" represents
the type of the service dependency):
+    :::java
+    import org.apache.felix.dm.lambda.DependencyManagerActivator;
 
-    method(S service)
-    method(S service, Map<String, Object> serviceProperties)
-    method(S service, Dictionary<String, Object> serviceProperties)
-    method(ServiceReference<S> serviceRef, S service),
-    method(ServiceReference<S> serviceRef)
-    method(Component serviceComponent)
-    method(Component serviceComponent, ServiceReference<S> serviceRef)
-    method(Component serviceComponent, S service) 
-    method(Component serviceComponent, ServiceReference<S> serviceRef, S service)
-
-And the "swap" callbacks accepts the following method signatures:
-
-    swapMethod(S oldService, S newService)
-    swapMethod(ServiceReference<S> oldRef, S old, ServiceReference<S> newRef,
S newService)
-    swapMethod(Component component, S oldService, S newService)
-    swapMethod(Component component, ServiceReference<S> oldRef, S old, ServiceReference<S>
newRef, S newService)
+    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")));
+        }
+    }
 
 Now you can also use a more type-safe callback using a Java 8 method reference:
 
@@ -190,8 +244,8 @@ Now you can also use a more type-safe ca
 
     public class Activator extends DependencyManagerActivator {
         @Override
-        public void activate() throws Exception {
-            component(comp -> comp.impl(Hello.class).withSrv(LogService.class, srv ->
srv.cb(Hello::setLog)));
+        public void init(BundleContext ctx, DependencyManager dm) throws Exception {
+            component(comp -> comp.impl(Hello.class).withSvc(LogService.class, srv ->
srv.add(Hello::setLog)));
         }
     }
 
@@ -202,16 +256,34 @@ or:
 
     public class Activator extends DependencyManagerActivator {
         @Override
-        public void activate() throws Exception {
-            component(comp -> comp.impl(Hello.class).withSrv(LogService.class, srv ->
srv.cb(Hello::setLog, Hello::unsetLog)));
+        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)));
         }
     }
 
-## Defining Service Dependency Object instance callback
+The following callback methods signatures are supported when using method references:
+
+For add/change/remove method references:
 
-Sometimes, you want to inject the dependency to a seperate object that is not part of the
component implementation classes.
-In this case, you can use the "`cbi`" method (which stands for "`callback instance`").
+    :::java
+    method(S service)
+    method(S service, ServiceReference<S> serviceRef),
+    method(S service, Map<String, Object> serviceProperties)
+    method(S service, Dictionary<String, Object> serviceProperties)
+    method(S service, Component serviceComponent)
+    method(S service, Component serviceComponent, ServiceReference<S> serviceRef)
+
+and for swap method references:
+
+    :::java
+    method(S oldService, S newService)
+    method(S oldService, S newService, Component component))
+    method(ServiceReference<S> oldRef, S old, ServiceReference<S> newRef, S newService)
+    method(ServiceReference<S> oldRef, S old, ServiceReference<S> newRef, S newService,
Component component)
+
+## Defining Service Dependency Object instance callback
 
+Sometimes, you want to inject the dependency to a separate object that is not part of the
component implementation classes.
 For example, the following example injects a dependency in a DependencyHandler instance:
 
     :::java
@@ -219,9 +291,9 @@ For example, the following example injec
 
     public class Activator extends DependencyManagerActivator {
         @Override
-        public void activate() throws Exception {
+        public void init(BundleContext ctx, DependencyManager dm) throws Exception {
             DependencyHandler depHandler = new DependencyHandler();
-            component(comp -> comp.impl(Hello.class).withSrv(LogService.class, srv ->
srv.cbi(depHandler, "setLog")));
+            component(comp -> comp.impl(Hello.class).withSvc(LogService.class, srv ->
srv.add(depHandler, "setLog")));
         }
     }
 
@@ -232,9 +304,9 @@ or using method reference:
 
     public class Activator extends DependencyManagerActivator {
         @Override
-        public void activate() throws Exception {
+        public void init(BundleContext ctx, DependencyManager dm) throws Exception {
             DependencyHandler depHandler = new DependencyHandler();
-            component(comp -> comp.impl(Hello.class).withSrv(LogService.class, srv ->
srv.cbi(depHandler::setLog)));
+            component(comp -> comp.impl(Hello.class).withSvc(LogService.class, srv ->
srv.add(depHandler::setLog)));
         }
     }
 
@@ -245,9 +317,9 @@ You can chain multiple callbacks:
 
     public class Activator extends DependencyManagerActivator {
         @Override
-        public void activate() throws Exception {
+        public void init(BundleContext ctx, DependencyManager dm) throws Exception {
             DependencyHandler depHandler = new DependencyHandler();
-            component(comp -> comp.impl(Hello.class).withSrv(LogService.class, srv ->
srv.cb(Hello::setLog).cbi(depHandler::setLog)));
+            component(comp -> comp.impl(Hello.class).withSvc(LogService.class, srv ->
srv.add(Hello::setLog).add(depHandler::setLog)));
         }
     }
 
@@ -262,12 +334,12 @@ Now you can pass properties directly to
 
     public class Activator extends DependencyManagerActivator {
         @Override
-        public void activate() throws Exception {
+        public void init(BundleContext ctx, DependencyManager dm) throws Exception {
             component(comp -> comp.impl(Hello.class).provides(HelloService.class, "p1",
"v1", "p2", 123));
         }
     }
 
-or if you build your program using the `-parameters` option, you can also use the "`FluentProperty`"
lambda that allows to declare
+or if you build your application using the `-parameters` javac option, you can also use the
"`FluentProperty`" lambda that allows to declare
 service properties as a suite of "`key -> value`" lambdas, like this:
 
     :::java
@@ -275,16 +347,114 @@ service properties as a suite of "`key -
 
     public class Activator extends DependencyManagerActivator {
         @Override
-        public void activate() throws Exception {
+        public void init(BundleContext ctx, DependencyManager dm) throws Exception {
             component(comp -> comp.impl(Hello.class).provides(HelloService.class, p1 ->
"v1", p2 -> 123));
         }
     }
 
+## Depending on a configuration.
+
+Configuration dependency can be defined using the "`withCnf`" ComponentBuilder method.
+
+Two families of callbacks are supported:
+
+- reflection based callbacks: you specify a callback method name
+- method reference callbacks: you specify a java8 method reference
+
+Callbacks may accept a Dictionary, a Component, or a user defined configuration type interface.
If you only specify a pid, by default the callback method name is assumed to be "updated".
+
+Configuration types are a new feature that allows you to specify an interface that is implemented
by DM and such interface is then injected to your callback instead of the actual Dictionary.
Using such configuration interface provides a way for creating type-safe configurations from
a actual Dictionary that is normally injected by Dependency Manager. The callback accepts
in argument an interface that you have to provide, and DM will inject a proxy that converts
method calls from your configuration-type to lookups in the actual map or dictionary. The
results of these lookups are then converted to the expected return type of the invoked configuration
method.
+As proxies are injected, no implementations of the desired configuration-type are necessary!
+
+The lookups performed are based on the name of the method called on the configuration type.
The method names are "mangled" to the following form: [lower case letter] [any valid character]*.
Method names starting with get or is (JavaBean convention) are stripped from these prefixes.
For example: given a dictionary with the key "foo" can be accessed from a configuration-type
using the following method names: foo(), getFoo() and isFoo().
+
+The return values supported are: primitive types (or their object wrappers), strings, enums,
arrays of primitives/strings, Collection types, Map types, Classes and interfaces. When an
interface is returned, it is treated equally to a configuration type, that is, it is returned
as a proxy.
+
+Arrays can be represented either as comma-separated values, optionally enclosed in square
brackets. For example: [ a, b, c ] and a, b,c are both considered an array of length 3 with
the values "a", "b" and "c". Alternatively, you can append the array index to the key in the
dictionary to obtain the same: a dictionary with "arr.0" => "a", "arr.1" => "b", "arr.2"
=> "c" would result in the same array as the earlier examples.
+
+Maps can be represented as single string values similarly as arrays, each value consisting
of both the key and value separated by a dot. Optionally, the value can be enclosed in curly
brackets. Similar to array, you can use the same dot notation using the keys. For example,
a dictionary with
+
+ "map" => "{key1.value1, key2.value2}"
+
+and a dictionary with
+
+ "map.key1" => "value1", "map2.key2" => "value2"
+
+result in the same map being returned. Instead of a map, you could also define an interface
with the methods getKey1() and getKey2 and use that interface as return type instead of a
Map.
+
+In case a lookup does not yield a value from the underlying map or dictionary, the following
rules are applied:
+
+- primitive types yield their default value, as defined by the Java Specification;
+- string, Classes and enum values yield null;
+- for arrays, collections and maps, an empty array/collection/map is returned;
+- for other interface types that are treated as configuration type a null-object is returned.

+
+Sample codes:
+
+Code example with a component that defines a Configuration Dependency using a specific callback
method reference, and the method accepts in argument a configuration type (the pid is assumed
to be the fqdn of the configuration type):
+
+    :::java
+    public interface MyConfig {
+        String getAddress();
+        int getPort();
+    }
+
+    public class ServiceImpl {
+        void modified(MyConfig cnf) {
+            if (cnf != null) {
+                String addr = cnf.getAddress();
+                int port = cnf.getPort();
+                ...
+            }
+        }
+    }
+
+    public class Activator extends DependencyManagerActivator {
+        public void init(BundleContext ctx, DependencyManager dm) throws Exception { 
+            component(comp -> comp.impl(ServiceImpl.class).withCnf(conf -> conf.update(MyConfig.class,
ServiceImpl::modified)));  
+        }
+    }
+ 
+
+Code example with a component that defines a Configuration Dependency using a specific callback
method reference which accepts a Dictionary in argument:
+
+    :::java
+    public class Activator extends DependencyManagerActivator {
+        public void init(BundleContext ctx, DependencyManager dm) throws Exception { 
+            component(comp -> comp
+               .impl(ServiceImpl.class)
+               .withCnf(conf -> conf.pid("my.pid").update(ServiceImpl::modified)));
+        }
+     }
+ 
+
+Code example which defines a configuration dependency injected in the "ServiceImpl.updated(Dictionary)"
callback:
+
+ 
+    :::java
+    public class Activator extends DependencyManagerActivator {
+        public void init(BundleContext ctx, DependencyManager dm) throws Exception { 
+            component(comp -> comp.impl(ServiceImpl.class).withCnf("my.pid"));
+        }
+    }
+ 
+
+Code example with a component that defines a Configuration Dependency using a specific callback
method name:
+
+ 
+    :::java
+    public class Activator extends DependencyManagerActivator {
+        public void init(BundleContext ctx, DependencyManager dm) throws Exception { 
+            component(comp -> comp.impl(ServiceImpl.class).withCnf(conf -> conf.pid("my.pid").update("modified")));
 
+        }
+     }
+ 
+
 ## Managing components outside of Activators.
 
 You can manage Components outside of the Activator by using some static factory methods from
the `DependencyManagerActivator` class.
 
-For example, consider a use case where you want to retrieve some informations from some already
injected services, and you then want to dynamically add more dependencies from your
+For example, consider a use case where you want to retrieve some information from some already
injected services, and you then want to dynamically add more dependencies from your
 `init` component callback. First let's look at the Activator:
 
     :::java
@@ -292,7 +462,7 @@ For example, consider a use case where y
 
     public class Activator extends DependencyManagerActivator {
         @Override
-        public void activate() throws Exception {
+        public void init(BundleContext ctx, DependencyManager dm) throws Exception {
             component(comp -> comp.impl(Pojo.class).withCnf("pojo.pid"));
         }
     }
@@ -311,7 +481,7 @@ what it has parsed, it will possibly add
     
         void init(Component c) { // lifecycle dm callback that allow you to add more dependencies
             if (xmlConfigurationRequiresEventAdmin) {
-                component(c, comp -> comp.withSrv(EventAdmin.class));
+                component(c, comp -> comp.withSvc(EventAdmin.class));
             }
         }
     }
@@ -348,10 +518,94 @@ And an example where you create a new DM
         volatile DependencyManager m_dm;
 
         void createComponent() {
-            component(m_dm, comp -> comp.impl(NewComponent.class).withSrv(LogService.Class,
EventAdmin.class));
+            component(m_dm, comp -> comp.impl(NewComponent.class).withSvc(LogService.Class,
EventAdmin.class));
+        }
+    }
+
+## Creating Aspect Components
+
+Like with the original DM API, you can create aspects (service interceptors), 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 
+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));
+        }
+    } 
+
+Same more concise example which does not declare the type of the lambda builder argument:
+
+    ::::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));
+        }
+    } 
+
+Same example, but using callbacks for injecting LogService and Dictionary services in the
aspect implementation class:
+
+    :::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)
+              .add(SpellCheckLogAspect::setLogService)
+              .withSvc(Dictionary.class, svc -> svc.add(SpellCheckLogAspect::setDictionary)));
+        }
+    } 
+
+## Creating Service Adapter Components
+
+DM service adapters allows to create adapter services when a given type of adapted service
is found in the OSGI registry.
+Using the "`adapter`" factory method, you can pass to it consumer of an `ServiceAdapterBuilder`
that
+can be used to construct a DM adapter component.
+
+Code example that adapts a "Device" service to an HttpServlet service. The adapter is created
using a ServiceAdapterBuilder that is passed to the lambda.
+
+    :::java 
+    public class Activator extends DependencyManagerActivator {
+        public void init(BundleContext ctx, DependencyManager dm) throws Exception { 
+            adapter(Device.class, (ServiceAdapterBuilder adapt) -> adapt.impl(DeviceServlet.class).provides(HttpServlet.class).properties(alias
-> "/device");                    
+        }
+    }
+
+Same more concise example which does not declare the type of lambda parameter:
+
+    :::java 
+    public class Activator extends DependencyManagerActivator {
+        public void init(BundleContext ctx, DependencyManager dm) throws Exception { 
+            adapter(Device.class, adapt -> adapt.impl(DeviceServlet.class).provides(HttpServlet.class).properties(alias
-> "/device");                    
         }
     }
 
+## Creating a Bundle Adapter component
+
+A Bundle Adapter is used to create a Component when a bundle that matches a given filter
is found.
+To build a DM adapter, you can use the "`bundleAdapter`" factory method: it takes in argument
a consumer of a
+BundleAdapterBuilder object, which is used to construct a real DM BundleAdapter component.
+
+Example that creates a BundleAdapter service for each started bundle (the bundle is added
using a method reference):
+
+    :::java 
+    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)
+               .add(BundleAdapterImpl::bundleStarted)
+               .withSvc(LogService.class, "(vendor=apache)")
+               .withSvc(EventAdmin.class, ConfigurationAdmin.class));
+        }
+    }
+ 
+Notice that the adapter also depends on three services (LogService, EventAdmin, and ConfigurationAdmin
services).
 
 ## CompletableFuture dependency.
 
@@ -379,10 +633,9 @@ So, the Activator looks like this:
 
     public class Activator extends DependencyManagerActivator {
         @Override
-        public void activate() throws Exception {
+        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));
+               .withCnf("foo.pid").withSvc(HttpClient.class).withSvc(Tracked.class, srv ->
srv.optional().add(Pojo::bindTracked));
         }
     }
 
@@ -409,7 +662,7 @@ injected in the "bindTracked" method:
             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)));
+            component(c, comp -> comp.withFuture(futurePage, future -> future.complete(this::setPage)));
         }
     
         void setPage(String content) {
@@ -435,81 +688,6 @@ Also, notice that when the page is injec
 synchronization at all because in DM, all lifecycle and dependency callbacks are safely scheduled
in a "serial queue" associated to the
 component.
 
-## Another Example with CompletableFuture and RxJava.
-
-We just introduced the new FutureDependency. Allowing to use a CompletableFuture as a dependency
is useful because CF is a powerful abstraction
-that allows to wrap any asynchronous events or async libraries with a standard jdk tool (CompletableFuture).
-In this section, we present a way to "wait for" RxJava "Observables" using DM.
-
-RxJava, like the CompletableFuture java8 tool, allows to react on events, but using non blocking
push paradigm.
-
-TODO: finish this section.
-
-## Comparing two activators using old and new API:
-
-Assume we have a `ServiceConsumer` which depends on the following services:
-
-- a required `ServiceProvider`: with "`(p1=v1)`" service filter and using a "`setProvider`"
callback.
-- a Configuration with pid="`org.apache.felix.dm.lambda.samples.hello.ServiceConsumer`".
-
-Now assume we have `ServiceProvider` provided with p1="v1" and p2=123 service properties;
and the provider also depends on:
-
-- a required `LogService` service (injected in class fields).
-- a required `EventAdmin` service  (injected in class fields).
-
-Then we have the following typical Activator (we define both components in the same Activator
for simplicity):
-
-    import org.apache.felix.dm.DependencyActivatorBase;
-    ...
-
-    :::java
-    public class Activator extends DependencyActivatorBase {
-        @Override
-        public void init(BundleContext ctx, DependencyManager dm) throws Exception {
-            // Declare our Consumer component
-    
-            Component consumer = dm.createComponent()
-    	        .setImplementation(ServiceConsumer.class)
-                .add(createServiceDependency().setService(ServiceProvider.class, "(p1=v1)").setRequired(true).setCallbacks("setProvider",
null))
-                .add(createConfigurationDependency().setPid("org.apache.felix.dm.lambda.samples.hello.ServiceConsumer"));
-            dm.add(consumer);
-    
-           // Declare our ServiceProvider service component
-    
-    	   Properties properties = new Properties();
-    	   Properties.put("p1", "v1");
-    	   properties.put("p2", 123);
-           Component provider = dm.createComponent()
-       	       .setImplementation(ServiceProviderImpl.class)
-    	       .setInterface(ServiceProvider.class.getName(), properties)
-    	       .add(createServiceDependency().setService(LogService.class).setRequired(true))
-    	       .add(createServiceDependency().setService(EventAdmin.class, null).setRequired(true));
-           dm.add(provider);
-        }
-    }
-
-Now, let's rework the above example, using the new dm-lambda API:
-
-    :::java
-    import org.apache.felix.dm.lambda.DependencyManagerActivator;
-    ...
-
-    public class Activator extends DependencyManagerActivator {
-        @Override
-        public void activate() throws Exception {
-            // Declare our Consumer component
-    
-            component(comp -> comp.impl(ServiceConsumer.class)
-                .withSrv(ServiceProvider.class, srv -> srv.filter("(p1=v1)").cb(ServiceConsumer::setProvider))
-                .withCnf(ServiceConsumer.class));
-                
-            // Declare our ServiceProvider service component:
-    
-            component(comp -> comp.impl(ServiceProviderImpl.class)
-                .provides(ServiceProvider.class, p1 -> "v1", p2 -> 123)
-                .withSrv(LogService.class, EventAdmin.class));
-    }
-
 ## Sample codes
 
 many samples codes are available from the distribution source release: Please take a look
at the following:
@@ -592,3 +770,7 @@ The Activator is then getting injected w
 Caution: if you are using a corporate http proxy, you have to fix the Activator in order
to configure the ip addr and port number of your
 http proxy.
 
+## Javadoc 
+
+You can find the javadoc for the new Dependency Manager Lambda library [here](../../../../apidocs/).
+




Mime
View raw message