Author: pderop
Date: Tue Feb  2 19:32:17 2016
New Revision: 1728179

URL: http://svn.apache.org/viewvc?rev=1728179&view=rev
Log:
Started documentation on upcomming dm-lambda.

Added:
    
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.mdtext

Modified: 
felix/site/trunk/content/documentation/subprojects/apache-felix-dependency-manager.mdtext
URL: 
http://svn.apache.org/viewvc/felix/site/trunk/content/documentation/subprojects/apache-felix-dependency-manager.mdtext?rev=1728179&r1=1728178&r2=1728179&view=diff
==============================================================================
--- 
felix/site/trunk/content/documentation/subprojects/apache-felix-dependency-manager.mdtext
 (original)
+++ 
felix/site/trunk/content/documentation/subprojects/apache-felix-dependency-manager.mdtext
 Tue Feb  2 19:32:17 2016
@@ -37,6 +37,7 @@ Below is the full table of contents.
 * [Performance 
Tuning](apache-felix-dependency-manager/guides/performance-tuning.html)
 * [Development](apache-felix-dependency-manager/guides/development.html)
 * [Design 
Patterns](apache-felix-dependency-manager/guides/design-patterns.html)
+* [Dependency Manager 
Lambda]((apache-felix-dependency-manager/guides/dm-lambda.html)
 * [Resource Adapters](apache-felix-dependency-manager/guides/resources.html)
 * [Javadocs](apache-felix-dependency-manager/guides/javadocs.html)
 
@@ -56,4 +57,4 @@ Below is the full table of contents.
     * 
[Resource](apache-felix-dependency-manager/reference/dependency-resource.html)
 * [Thread Model](apache-felix-dependency-manager/reference/thread-model.html)
 * [External Links and 
Articles](apache-felix-dependency-manager/reference/external-links.html)
-       
+

Added: 
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=1728179&view=auto
==============================================================================
--- 
felix/site/trunk/content/documentation/subprojects/apache-felix-dependency-manager/guides/dm-lambda.mdtext
 (added)
+++ 
felix/site/trunk/content/documentation/subprojects/apache-felix-dependency-manager/guides/dm-lambda.mdtext
 Tue Feb  2 19:32:17 2016
@@ -0,0 +1,450 @@
+Title: 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.
+
+## Principle
+
+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 you can then build the 
objects and add them to
+the DependencyManager class automatically.
+
+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.
+
+(There is currently no builders for DM ResourceDependency and ResourceAdapter 
objects, but they will be supported soon).
+
+There are two ways to use these builders:
+
+You can first instantiate builders using some of the convenient factory 
methods available from the DependencyManagerActivator class, which is the new 
base class
+for dm-lambda activators:
+
+    :::java
+    import static org.apache.felix.dm.lambda.DependencyManagerActivator.*;
+
+    public class Activator extends DependencyActivatorBase {
+        @Override
+        public void init(BundleContext ctx, DependencyManager dm) throws 
Exception {
+            Component comp = component().impl(Hello.class).build();
+           m_dm.add(comp);
+        }
+    }
+
+The `component()` method returns a `ComponentBuilder` and the call to `build` 
at the end of the call chain returns the actual DM Component object.
+
+Now, most of the time, in an Activator, you usually almost always create and 
immediately add the component in the `dm` object.
+So, in order to reduce the "`code ceremony`", you can also use a special 
overloaded factory method that accepts a lambda which takes as argument a
+`Consumer<ComponentBuilder>` parameter.
+So, the lambda has just to invoke the chain of necessary methods from the 
builder, without having to call `build` and add the returned Component to the 
`dm` object.
+
+The following is the same as above, using a consumer<ComponentBuilder> lambda 
expression:
+
+    :::java
+    public class Activator extends DependencyActivatorBase {
+        @Override
+        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:
+
+    :::java
+    public class Activator extends DependencyActivatorBase {
+        @Override
+        public void init(BundleContext ctx, DependencyManager dm) throws 
Exception {
+            component(comp -> comp.impl(Hello.class));
+        }
+    }
+
+## 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.
+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
+    public class Activator extends DependencyActivatorBase {
+        @Override
+        public void init(BundleContext ctx, DependencyManager dm) throws 
Exception {
+            component(comp -> comp.impl(Hello.class).withSrv(LogService.class, 
(ServiceDependencyBuilder srv) -> srv.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:
+
+    :::java
+    public class Activator extends DependencyActivatorBase {
+        @Override
+        public void init(BundleContext ctx, DependencyManager dm) throws 
Exception {
+            component(comp -> comp.impl(Hello.class).withSrv(LogService.class, 
srv -> srv.filter("(vendor=apache)")));
+        }
+    }
+
+If you depend on multiple required services (with no filters), you can declare 
the services in one shot like this:
+
+    :::java
+    public class Activator extends DependencyActivatorBase {
+        @Override
+        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)); 
+        }
+    }
+
+## Defining Service Dependency Component's 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:
+
+    :::java
+    public class Activator extends DependencyActivatorBase {
+        @Override
+        public void init(BundleContext ctx, DependencyManager dm) throws 
Exception {
+            component(comp -> comp.impl(Hello.class).withSrv(LogService.class, 
srv -> srv.cb("setLog")));
+        }
+    }
+
+The `cb` method accepts a varargs of strings (up to 4 method names):
+
+1. when using one argument, the first argument is used as the `add` callback.
+1. when using two argument, the first argument is used as the `add` callback, 
and the second one as the `remove` callback.
+1. when using three arguments, the first argument 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 given argument 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.
+
+The add/change/remove callbacks accepts the following kind of method 
signatures ("S" represents the type of the service dependency):
+
+    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)
+
+Now you can also use a more type-safe callback using a Java 8 method reference:
+
+    :::java
+    public class Activator extends DependencyActivatorBase {
+        @Override
+        public void init(BundleContext ctx, DependencyManager dm) throws 
Exception {
+            component(comp -> comp.impl(Hello.class).withSrv(LogService.class, 
srv -> srv.cb(Hello::setLog)));
+        }
+    }
+
+or:
+
+    :::java
+    public class Activator extends DependencyActivatorBase {
+        @Override
+        public void init(BundleContext ctx, DependencyManager dm) throws 
Exception {
+            component(comp -> comp.impl(Hello.class).withSrv(LogService.class, 
srv -> srv.cb(Hello::setLog, Hello::unsetLog)));
+        }
+    }
+
+## Defining Service Dependency Object instance callback
+
+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`").
+
+For example, the following example injects a dependency in a DependencyHandler 
instance:
+
+    :::java
+    public class Activator extends DependencyActivatorBase {
+        @Override
+        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")));
+        }
+    }
+
+or using method reference:
+
+    :::java
+    public class Activator extends DependencyActivatorBase {
+        @Override
+        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)));
+        }
+    }
+
+You can chain multiple callbacks:
+
+    :::java
+    public class Activator extends DependencyActivatorBase {
+        @Override
+        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)));
+        }
+    }
+
+## Providing a service
+
+When a component provides a service with some properties, so far it was 
necessary to create a Dictionary and pass it to the `Component.setInterface()` 
method.
+
+Now you can now pass properties as varargs of properties (a suite of key-value 
properties):
+
+    :::java
+    public class Activator extends DependencyActivatorBase {
+        @Override
+        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 `-parameter` option, you can also use 
the "FluentProperty" lambda that allows to declare
+service properties as a suite of FlientProperty lambdas:
+
+    :::java
+    public class Activator extends DependencyActivatorBase {
+        @Override
+        public void init(BundleContext ctx, DependencyManager dm) throws 
Exception {
+            component(comp -> 
comp.impl(Hello.class).provides(HelloService.class, p1 -> "v1", p2 -> 123));
+        }
+    }
+
+## Managing components outside of Activators.
+
+You can create Components outside of the Activator by using some static 
factory methods from the `DependencyManagerActivator` class.
+
+For example, considere 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
+`init` component callback. First let's look at the Activator:
+
+    :::java
+    public class Activator extends DependencyActivatorBase {
+        @Override
+        public void init(BundleContext ctx, DependencyManager dm) throws 
Exception {
+            component(comp -> comp.impl(Pojo.class).withCnf("pojo.pid"));
+        }
+    }
+
+Here, we define a Configuration dependency with a "pojo.pid" configuration 
pid. So, now, the Pojo will then for example be able to parse an xml from the 
configuration, and depending on
+what it has parsed, it will possibly add more dependencies, like this:
+
+    import static org.apache.felix.dm.lambda.DependencyManagerActivator.*;
+
+    :::java
+    public class Pojo {
+        void updated(Dictionary conf) throws Exception {
+            parseXml(conf.get("some.xml.configuration"));
+        }
+
+       void init(Component c) { // lifecycle dm callback that allow you to add 
more dependencies
+            if (xmlConfigurationRequiresEventAdmin) {
+               component(c, comp -> comp.withSrv(EventAdmin.class));
+            }
+       }
+    }
+
+The available variety of factory methods allows you to also create some DM 
objects and add them manually, like:
+
+    :::java
+    public class Pojo {
+        void updated(Dictionary conf) throws Exception {
+            parseXml(conf.get("some.xml.configuration"));
+        }
+
+       void init(Component c) { // lifecycle dm callback that allow you to add 
more dependencies
+            if (xmlConfigurationRequiresEventAdmin) {
+               DependencyManager dm = c.getDependencyManager();
+               ServiceDependency dep = serviceDependency(c, 
EventAdmin.class).filter("(vendor=felix)").build();
+               dm.add(dep);
+            }
+       }
+    }
+
+## CompletableFuture dependency.
+
+The new library provides a new feature; you can now make your component 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.
+
+So, naturally, you can write from your init() method something 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)));
+       }
+
+       // Inject our HttpServer that is listening
+       void serverReady(HttpServer server) { ... }
+
+       void start() {
+          // at this point we are fully started
+       }
+       
+    }
+
+and your HttpService will be registered only once the server is listening.
+
+## 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:
+
+### 
org.apache.felix.dependencymanager.lambda.samples/src/org/apache/felix/dm/lambda/samples/hello/
+
+This sample provides a DM Activator declaring one service consumer and a 
service provider. The
+ServiceConsumer is also depending on a configuration pid  (see 
org.apache.felix.dependencymanager.samples.hello.Configurator).
+
+### 
org.apache.felix.dependencymanager.lambda.samples/src/org/apache/felix/dm/lambda/samples/compositefactory/
+
+This Activator is an example usage of DM composite components. A composite 
component is implemented
+using a composition of multiple object instances, which are used to implement 
a given service.
+
+The sample also uses a Factory approach in order to instantiate the 
composition of objects: A
+"CompositionManager" is first injected with a Configuration that can possibly 
be used to create
+and configure all the composites.
+
+Dependencies are injected is some of the component implementation instances, 
using java8 method references. For instance,
+the LogService is only injected in the ProviderImpl and the ProviderComposite1 
class and not in the ProviderComposite2 class.
+
+### 
org.apache.felix.dependencymanager.lambda.samples/src/org/apache/felix/dm/lambda/samples/device/
+
+This is an example showing a Dependency Manager "Adapter" in action. Two kinds 
of services are
+registered in the registry: some Device, and some DeviceParameter services. 
For each Device (having
+a given id), there is also a corresponding "DeviceParameter" service, having 
the same id.
+
+Then a "DeviceAccessImpl" adapter service is defined: it is used to "adapt" 
the "Device" service to
+a "DeviceAccess" service, which provides the union of each pair of 
Device/DeviceParameter having the
+same device.id . The adapter also dynamically propagate the service properties 
of the adapted Device
+service.
+
+### 
org.apache.felix.dependencymanager.lambda.samples/src/org/apache/felix/dm/lambda/samples/dictionary/
+
+This sample shows a "SpellChecker" application which provides a
+"dictionary:spellcheck" GOGO shell command. The GOGO "dictionary:spellcheck" 
command accepts a
+string as parameter, which is checked for proper exactness. The SpellChecker 
class has a
+required/multiple (1..N) dependency over every available "DictionaryService" 
services, which are
+internally used by the SpellChecker command, when checking word exactness.
+
+A DictionaryService is defined using a FactoryConfigurationAdapterService , 
allowing to instantiate
+many "DictionaryService" instances for each configuration that are added to the
+factory pid "Spell Checker Configuration (api)" from web console.
+The factory pid configuration metatypes are defined using the bnd "metatype" 
annotations
+(see DictionaryConfiguration.java).
+
+The DictionaryService is decorated with a DictionaryAspect, which you can 
instantiate by adding a
+configuration to the "Spell Checker Aspect Dictionary (api)" pid from web 
console. The
+aspect configuration metatype is also declared using the bnd metatype 
annotations (see
+DictionaryAspectConfiguration.java). 
+
+Before running this sample, go to webconsole, and add some words in the Spell 
Checker Configuration (api) factory PID, and
+in the Spell Checker Aspect Dictionary (api) PID.
+
+Then go to gogo shell, and type dm help. You will normally see the 
dictionary:spellcheck command.
+Type dictionary:spellcheck with some words configured either in the spell 
checker configuration, or in the spell checker aspect configuration,
+and the dictionary will check for proper word exactness in the configuration.
+
+### 
org.apache.felix.dependencymanager.lambda.samples/src/org/apache/felix/dm/lambda/samples/factory/
+
+This sample is an example usage of DM components that are created using a 
Factory object. 
+The Factory is defined using java8 method references.
+
+### 
org.apache.felix.dependencymanager.lambda.samples/src/org/apache/felix/dm/lambda/samples/future/
+
+The purpose of this sample is to show an example usage of the new 
"CompletableFuture" dependency that has been
+added in the dm-lambda library. CompletableFuture java8 class provides 
functional operations and promotes an asynchronous event-driven model.
+
+In such model, you can use the new dm-lambda library to add dependencies on 
asynchronous events using the standard JDK CompletableFuture class.
+
+In this example, the Activator first defines a PageLink component that is used 
to download a given page from the web. The service then parses 
+the content of the page and returns all available hrefs (links) found from the 
web page.
+
+The PageLink is initialized with the Felix web site URL, which is 
asynchronously downloaded from the PageLink::init method, using a 
CompletableFuture. 
+The CF is then added as a "FutureDependency" in the PageLinkImpl.init() 
method, and when the CF completes, the PageLinkImpl.start() callback is invoked 
+and the service is registered.
+
+The Activator is then getting injected with the PageLink service, and displays 
the links (hrefs) found from the Felix web site.
+
+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.
+


Reply via email to